import 'package:bart/bart/bart_model.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:kasy_kit/components/components.dart';
import 'package:kasy_kit/core/haptics/kasy_haptics.dart';
import 'package:kasy_kit/core/theme/theme.dart';
import 'package:kasy_kit/core/widgets/kasy_hover.dart';
import 'package:kasy_kit/features/home/home_components_preview_page.dart';

/// Previews só instanciam os widgets públicos do kit (`components.dart` +
/// tema). Rows / scroll / espaçamentos são apenas layout da vitrine —
/// comportamento visual vem das props do componente (ex.: `KasyAccordion.surfaceRadius`,
/// `KasyButton.borderRadius`). Presets opcionais: [KasyAvatarGradients],
/// [KasyAvatarDemoPhotos] (pacote avatar).
class ComponentPreviewDefinition {
  final String title;
  final List<ComponentPreviewVariant> variants;

  const ComponentPreviewDefinition({
    required this.title,
    required this.variants,
  });
}

ComponentPreviewDefinition? getComponentPreviewDefinition(
  String componentName,
) {
  switch (componentName) {
    case 'Accordion':
      return const ComponentPreviewDefinition(
        title: 'Accordion',
        variants: [
          ComponentPreviewVariant(
            label: 'Default variant',
            builder: _buildAccordionDefaultVariant,
          ),
          ComponentPreviewVariant(
            label: 'Surface variant',
            builder: _buildAccordionSurfaceVariant,
          ),
          ComponentPreviewVariant(
            label: 'Multiple expansion',
            builder: _buildAccordionElevatedCardVariant,
          ),
        ],
      );
    case 'Alert':
      return const ComponentPreviewDefinition(
        title: 'Alert',
        variants: [
          ComponentPreviewVariant(
            label: 'Default & Accent',
            builder: _buildAlertDefaultAccentVariant,
          ),
          ComponentPreviewVariant(
            label: 'Success, Warning, Danger',
            builder: _buildAlertSemanticVariant,
          ),
          ComponentPreviewVariant(
            label: 'With buttons',
            builder: _buildAlertWithButtonsVariant,
          ),
          ComponentPreviewVariant(
            label: 'With custom indicator',
            builder: _buildAlertLoadingVariant,
          ),
        ],
      );
    case 'AppBar':
      return const ComponentPreviewDefinition(
        title: 'AppBar',
        variants: [
          ComponentPreviewVariant(
            label: 'Subpage',
            builder: _buildAppBarSubpageVariant,
          ),
          ComponentPreviewVariant(
            label: 'Subpage Simple',
            builder: _buildAppBarSubpageSimpleVariant,
          ),
          ComponentPreviewVariant(
            label: 'Subpage Actions',
            builder: _buildAppBarSubpageActionsVariant,
          ),
        ],
      );
    case 'Button':
      return const ComponentPreviewDefinition(
        title: 'Button',
        variants: [
          ComponentPreviewVariant(
            label: 'Sizes',
            builder: _buildButtonSizesVariant,
          ),
          ComponentPreviewVariant(
            label: 'Variants',
            builder: _buildButtonVariantsVariant,
          ),
          ComponentPreviewVariant(
            label: 'Hover fill effect',
            builder: _buildButtonHoverFillVariant,
          ),
          ComponentPreviewVariant(
            label: 'Disabled state',
            builder: _buildButtonDisabledStateVariant,
          ),
          ComponentPreviewVariant(
            label: 'Width/alignment control',
            builder: _buildButtonWidthAlignmentVariant,
          ),
          ComponentPreviewVariant(
            label: 'With icons',
            builder: _buildButtonWithIconsVariant,
          ),
          ComponentPreviewVariant(
            label: 'Icon only',
            builder: _buildButtonIconOnlyVariant,
          ),
          ComponentPreviewVariant(
            label: 'Custom styling',
            builder: _buildButtonCustomStylingVariant,
          ),
          ComponentPreviewVariant(
            label: 'Layout transitions demo',
            builder: _buildButtonLayoutTransitionsVariant,
          ),
        ],
      );
    case 'BottomSheet':
      return const ComponentPreviewDefinition(
        title: 'BottomSheet',
        variants: [
          ComponentPreviewVariant(
            label: 'Basic',
            builder: _buildBottomSheetBasic,
          ),
          ComponentPreviewVariant(
            label: 'Tones',
            builder: _buildBottomSheetTones,
          ),
          ComponentPreviewVariant(
            label: 'Detached',
            builder: _buildBottomSheetDetached,
          ),
          ComponentPreviewVariant(
            label: 'With blur overlay',
            builder: _buildBottomSheetBlurOverlay,
          ),
          ComponentPreviewVariant(
            label: 'Scrollable with snap points',
            builder: _buildBottomSheetScrollableSnap,
          ),
          ComponentPreviewVariant(
            label: 'Page sheet',
            builder: _buildBottomSheetNativeModal,
          ),
          ComponentPreviewVariant(
            label: 'Bottom sheet with text field',
            builder: _buildBottomSheetTextInput,
          ),
          ComponentPreviewVariant(
            label: 'Scrollable',
            builder: _buildBottomSheetScrollable,
          ),
          ComponentPreviewVariant(
            label: 'OTP verification',
            builder: _buildBottomSheetOtpVerification,
          ),
          ComponentPreviewVariant(
            label: 'PIN verification',
            builder: _buildBottomSheetPinVerification,
          ),
        ],
      );
    case 'Card':
      return const ComponentPreviewDefinition(
        title: 'Card',
        variants: [
          ComponentPreviewVariant(
            label: 'Variants',
            builder: _buildCardVariants,
          ),
          ComponentPreviewVariant(
            label: 'Product card',
            builder: _buildCardProduct,
          ),
          ComponentPreviewVariant(
            label: 'Community cards',
            builder: _buildCardCommunity,
          ),
          ComponentPreviewVariant(
            label: 'Event list',
            builder: _buildCardEventList,
          ),
          ComponentPreviewVariant(label: 'Hero card', builder: _buildCardHero),
          ComponentPreviewVariant(
            label: 'Interactive',
            builder: _buildCardInteractiveAll,
          ),
        ],
      );
    case 'Checkbox':
      return const ComponentPreviewDefinition(
        title: 'Checkbox',
        variants: [
          ComponentPreviewVariant(
            label: 'Basic usage',
            builder: _buildCheckboxBasicUsage,
          ),
          ComponentPreviewVariant(
            label: 'States',
            builder: _buildCheckboxStates,
          ),
          ComponentPreviewVariant(
            label: 'Custom styles',
            builder: _buildCheckboxCustomStyles,
          ),
        ],
      );
    case 'Chip':
      return const ComponentPreviewDefinition(
        title: 'Chip',
        variants: [
          ComponentPreviewVariant(
            label: 'Action',
            builder: _buildActionChipVariant,
          ),
          ComponentPreviewVariant(
            label: 'Filter',
            builder: _buildFilterChipVariant,
          ),
        ],
      );
    case 'Dialog':
      return const ComponentPreviewDefinition(
        title: 'Dialog',
        variants: [
          ComponentPreviewVariant(
            label: 'Basic dialog',
            builder: _buildDialogBasic,
          ),
          ComponentPreviewVariant(
            label: 'Dialog with blur backdrop',
            builder: _buildDialogBlurBackdrop,
          ),
          ComponentPreviewVariant(
            label: 'Dialog with TextField',
            builder: _buildDialogTextInput,
          ),
          ComponentPreviewVariant(
            label: 'Dialog with long content',
            builder: _buildDialogLongContent,
          ),
        ],
      );
    case 'Badge':
      return const ComponentPreviewDefinition(
        title: 'Badge',
        variants: [
          ComponentPreviewVariant(
            label: 'Default',
            builder: _buildBadgeDefault,
          ),
          ComponentPreviewVariant(label: 'Colors', builder: _buildBadgeColors),
          ComponentPreviewVariant(label: 'Sizes', builder: _buildBadgeSizes),
          ComponentPreviewVariant(
            label: 'Variants',
            builder: _buildBadgeVariants,
          ),
          ComponentPreviewVariant(
            label: 'Placements',
            builder: _buildBadgePlacements,
          ),
          ComponentPreviewVariant(label: 'Dot badge', builder: _buildBadgeDot),
          ComponentPreviewVariant(
            label: 'With content',
            builder: _buildBadgeWithContent,
          ),
        ],
      );
    case 'TextField':
      return const ComponentPreviewDefinition(
        title: 'TextField',
        variants: [
          ComponentPreviewVariant(
            label: 'Default',
            builder: _buildBasicTextFieldVariant,
          ),
          ComponentPreviewVariant(
            label: 'Label & Description',
            builder: _buildTextFieldWithLabelDescriptionVariant,
          ),
          ComponentPreviewVariant(
            label: 'Standard',
            builder: _buildTextFieldStandard,
          ),
          ComponentPreviewVariant(
            label: 'Character Limit',
            builder: _buildTextFieldCharacterLimit,
          ),
          ComponentPreviewVariant(
            label: 'Variants',
            builder: _buildTextFieldVariantsVariant,
          ),
          ComponentPreviewVariant(
            label: 'States',
            builder: _buildTextFieldStates,
          ),
          ComponentPreviewVariant(
            label: 'With Icons',
            builder: _buildTextFieldWithIcon,
          ),
          ComponentPreviewVariant(
            label: 'Multiline',
            builder: _buildTextFieldMultiline,
          ),
        ],
      );
    case 'TextArea':
      return const ComponentPreviewDefinition(
        title: 'TextArea',
        variants: [
          ComponentPreviewVariant(
            label: 'Basic TextArea',
            builder: _buildTextAreaBasic,
          ),
          ComponentPreviewVariant(
            label: 'With Label & Description',
            builder: _buildTextAreaWithLabelDescription,
          ),
          ComponentPreviewVariant(
            label: 'States',
            builder: _buildTextAreaStates,
          ),
        ],
      );
    case 'TextFieldOTP':
      return const ComponentPreviewDefinition(
        title: 'TextFieldOTP',
        variants: [
          ComponentPreviewVariant(
            label: 'Default',
            builder: _buildTextFieldOTPDefault,
          ),
          ComponentPreviewVariant(
            label: 'Error',
            builder: _buildTextFieldOTPError,
          ),
          ComponentPreviewVariant(
            label: 'Four Digits',
            builder: _buildTextFieldOTPFourDigits,
          ),
          ComponentPreviewVariant(
            label: 'With Placeholder',
            builder: _buildTextFieldOTPWithPlaceholder,
          ),
          ComponentPreviewVariant(
            label: 'Disabled',
            builder: _buildTextFieldOTPDisabled,
          ),
          ComponentPreviewVariant(
            label: 'With Pattern',
            builder: _buildTextFieldOTPWithPattern,
          ),
          ComponentPreviewVariant(
            label: 'Custom Styles',
            builder: _buildTextFieldOTPCustomStyles,
          ),
          ComponentPreviewVariant(
            label: 'With bottom sheet',
            builder: _buildTextFieldOTPBottomSheet,
          ),
        ],
      );
    case 'Toast':
      return const ComponentPreviewDefinition(
        title: 'Toast',
        variants: [
          ComponentPreviewVariant(
            label: 'Default variants',
            builder: _buildToastDefaultVariants,
          ),
          ComponentPreviewVariant(
            label: 'Placement variants',
            builder: _buildToastPlacementVariants,
          ),
          ComponentPreviewVariant(
            label: 'From native modal',
            builder: _buildToastModalPreview,
          ),
          ComponentPreviewVariant(
            label: 'Custom toasts',
            builder: _buildToastCustomVariants,
          ),
          ComponentPreviewVariant(
            label: 'Static preview',
            builder: _buildToastStaticPreview,
          ),
        ],
      );
    case 'Avatar':
      return const ComponentPreviewDefinition(
        title: 'Avatar',
        variants: [
          ComponentPreviewVariant(
            label: 'Sizes',
            builder: _buildAvatarSizesVariant,
          ),
          ComponentPreviewVariant(
            label: 'Default text fallback',
            builder: _buildAvatarDefaultTextFallbackVariant,
          ),
          ComponentPreviewVariant(
            label: 'Soft text fallback',
            builder: _buildAvatarSoftTextFallbackVariant,
          ),
          ComponentPreviewVariant(
            label: 'Default icon fallback',
            builder: _buildAvatarDefaultIconFallbackVariant,
          ),
          ComponentPreviewVariant(
            label: 'Soft icon fallback',
            builder: _buildAvatarSoftIconFallbackVariant,
          ),
          ComponentPreviewVariant(
            label: 'Custom fallback',
            builder: _buildAvatarCustomFallbackVariant,
          ),
          ComponentPreviewVariant(
            label: 'Avatar group',
            builder: _buildAvatarGroupVariant,
          ),
          ComponentPreviewVariant(
            label: 'Custom styles',
            builder: _buildAvatarCustomStylesVariant,
          ),
        ],
      );
    case 'Hover':
      return const ComponentPreviewDefinition(
        title: 'Hover',
        variants: [
          ComponentPreviewVariant(
            label: 'List rows',
            builder: _buildTappableRowListVariant,
          ),
          ComponentPreviewVariant(
            label: 'Custom buttons',
            builder: _buildTappableRowCardVariant,
          ),
          ComponentPreviewVariant(
            label: 'Clickable cards',
            builder: _buildTappableRowGroupVariant,
          ),
        ],
      );
    case 'Tabs':
      return const ComponentPreviewDefinition(
        title: 'Tabs',
        variants: [
          ComponentPreviewVariant(
            label: 'Primary variant',
            builder: _buildTabsPrimaryVariant,
          ),
          ComponentPreviewVariant(
            label: 'Secondary variant',
            builder: _buildTabsSecondaryVariant,
          ),
          ComponentPreviewVariant(
            label: 'Fill mode',
            builder: _buildTabsFillModeVariant,
          ),
        ],
      );
    case 'Sidebar':
      return const ComponentPreviewDefinition(
        title: 'Sidebar',
        variants: [
          ComponentPreviewVariant(
            label: 'Drawer demo',
            builder: _buildSidebarVariant,
          ),
        ],
      );
    case 'Skeleton':
      return const ComponentPreviewDefinition(
        title: 'Skeleton',
        variants: [
          ComponentPreviewVariant(
            label: 'Card skeleton',
            builder: _buildSkeletonCardVariant,
          ),
          ComponentPreviewVariant(
            label: 'List skeleton',
            builder: _buildSkeletonListVariant,
          ),
          ComponentPreviewVariant(
            label: 'Text skeletons',
            builder: _buildSkeletonTextVariant,
          ),
          ComponentPreviewVariant(
            label: 'Profile skeleton',
            builder: _buildSkeletonProfileVariant,
          ),
          ComponentPreviewVariant(
            label: 'Grid skeleton',
            builder: _buildSkeletonGridVariant,
          ),
        ],
      );
    case 'SwipeAction':
      return const ComponentPreviewDefinition(
        title: 'SwipeAction',
        variants: [
          ComponentPreviewVariant(
            label: 'Destructive (delete)',
            builder: _buildSwipeActionDestructive,
          ),
          ComponentPreviewVariant(
            label: 'Neutral (archive)',
            builder: _buildSwipeActionNeutral,
          ),
          ComponentPreviewVariant(
            label: 'With confirm',
            builder: _buildSwipeActionWithConfirm,
          ),
        ],
      );
    default:
      return null;
  }
}

// ─────────────────────────────────────────────────────────────────────────────
// Sidebar — drawer demo
// ─────────────────────────────────────────────────────────────────────────────

Widget _buildSidebarVariant(BuildContext context) => const _SidebarPreview();

final List<BartMenuRoute> _kSidebarMockRoutes = [
  BartMenuRoute.bottomBar(
    label: 'Home',
    icon: KasyIcons.home,
    path: '/home',
    pageBuilder: (parentCtx, tabCtx, settings) => const SizedBox.shrink(),
  ),
  BartMenuRoute.bottomBar(
    label: 'Notifications',
    icon: KasyIcons.notification,
    path: '/notifications',
    pageBuilder: (parentCtx, tabCtx, settings) => const SizedBox.shrink(),
  ),
  BartMenuRoute.bottomBar(
    label: 'Profile',
    icon: KasyIcons.person,
    path: '/profile',
    pageBuilder: (parentCtx, tabCtx, settings) => const SizedBox.shrink(),
  ),
  BartMenuRoute.bottomBar(
    label: 'Settings',
    icon: KasyIcons.settings,
    path: '/settings',
    pageBuilder: (parentCtx, tabCtx, settings) => const SizedBox.shrink(),
  ),
];

class _SidebarPreview extends StatefulWidget {
  const _SidebarPreview();

  @override
  State<_SidebarPreview> createState() => _SidebarPreviewState();
}

class _SidebarPreviewState extends State<_SidebarPreview> {
  final ValueNotifier<int> _currentItem = ValueNotifier(0);

  @override
  void dispose() {
    _currentItem.dispose();
    super.dispose();
  }

  void _openDrawer(BuildContext context, {required bool fromEnd}) {
    final routes = _kSidebarMockRoutes;
    showGeneralDialog<void>(
      context: context,
      barrierDismissible: true,
      barrierLabel: 'Dismiss',
      barrierColor: Colors.black.withValues(alpha: 0.42),
      transitionDuration: const Duration(milliseconds: 290),
      pageBuilder: (ctx, anim, secAnim) => Align(
        alignment:
            fromEnd ? Alignment.centerRight : Alignment.centerLeft,
        child: SizedBox(
          height: double.infinity,
          child: ValueListenableBuilder<int>(
            valueListenable: _currentItem,
            builder: (builderCtx, currentIndex, child) =>
                kasySidebarBuilder(routes, (i) {
              _currentItem.value = i;
            }, _currentItem),
          ),
        ),
      ),
      transitionBuilder: (ctx, anim, secAnim, child) {
        final curved = CurvedAnimation(
          parent: anim,
          curve: Curves.easeOutCubic,
        );
        return SlideTransition(
          position: Tween<Offset>(
            begin: Offset(fromEnd ? 1.0 : -1.0, 0),
            end: Offset.zero,
          ).animate(curved),
          child: FadeTransition(
            opacity: Tween<double>(begin: 0.85, end: 1.0).animate(curved),
            child: child,
          ),
        );
      },
    );
  }

  @override
  Widget build(BuildContext context) {
    return Column(
      mainAxisSize: MainAxisSize.min,
      crossAxisAlignment: CrossAxisAlignment.stretch,
      children: [
        Padding(
          padding: const EdgeInsets.symmetric(horizontal: KasySpacing.md),
          child: _previewIntrinsicLaunch(
            KasyButton(
              label: 'Open Left',
              variant: KasyButtonVariant.soft,
              onPressed: () => _openDrawer(context, fromEnd: false),
            ),
          ),
        ),
        const SizedBox(height: KasySpacing.sm),
        Padding(
          padding: const EdgeInsets.symmetric(horizontal: KasySpacing.md),
          child: _previewIntrinsicLaunch(
            KasyButton(
              label: 'Open Right',
              variant: KasyButtonVariant.soft,
              onPressed: () => _openDrawer(context, fromEnd: true),
            ),
          ),
        ),
      ],
    );
  }
}


// ─────────────────────────────────────────────────────────────────────────────
// Tabs — interactive demos
// ─────────────────────────────────────────────────────────────────────────────

Widget _buildTabsPrimaryVariant(BuildContext context) =>
    const _TabsPrimaryPreview();

Widget _buildTabsSecondaryVariant(BuildContext context) =>
    const _TabsSecondaryPreview();

Widget _buildTabsFillModeVariant(BuildContext context) =>
    const _TabsFillModePreview();

// ── Primary variant ────────────────────────────────────────────────────────

class _TabsPrimaryPreview extends StatefulWidget {
  const _TabsPrimaryPreview();

  @override
  State<_TabsPrimaryPreview> createState() => _TabsPrimaryPreviewState();
}

class _TabsPrimaryPreviewState extends State<_TabsPrimaryPreview> {
  int _index = 0;

  static const List<String> _tabs = ['Overview', 'Details', 'Settings'];

  static const List<String> _content = [
    'Overview content — a summary of the most important information at a glance.',
    'Details content — in-depth information about each specific aspect.',
    'Settings content — configure preferences and options here.',
  ];

  @override
  Widget build(BuildContext context) {
    final KasyColors c = context.colors;

    return Column(
      crossAxisAlignment: CrossAxisAlignment.stretch,
      mainAxisSize: MainAxisSize.min,
      children: [
        KasyTabs(
          tabs: _tabs,
          selectedIndex: _index,
          onTabSelected: (i) => setState(() => _index = i),
        ),
        const SizedBox(height: KasySpacing.md),
        AnimatedSwitcher(
          duration: const Duration(milliseconds: 200),
          child: KasyCard(
            key: ValueKey(_index),
            padding: const EdgeInsets.all(KasySpacing.md),
            child: Text(
              _content[_index],
              style: context.textTheme.bodyMedium?.copyWith(
                color: c.onSurface.withValues(alpha: 0.75),
                height: 1.5,
              ),
            ),
          ),
        ),
        const SizedBox(height: KasySpacing.lg),
        // Disabled tab demo
        Text(
          'WITH DISABLED TAB',
          style: context.textTheme.labelSmall?.copyWith(
            color: c.muted,
            letterSpacing: 1.2,
            fontWeight: FontWeight.w700,
          ),
        ),
        const SizedBox(height: KasySpacing.sm),
        KasyTabs.items(
          items: const [
            KasyTabItem(label: 'Active'),
            KasyTabItem(label: 'Disabled', enabled: false),
            KasyTabItem(label: 'Active'),
          ],
          selectedIndex: 0,
          onTabSelected: (_) {},
        ),
      ],
    );
  }
}

// ── Secondary variant ──────────────────────────────────────────────────────

class _TabsSecondaryPreview extends StatefulWidget {
  const _TabsSecondaryPreview();

  @override
  State<_TabsSecondaryPreview> createState() => _TabsSecondaryPreviewState();
}

class _TabsSecondaryPreviewState extends State<_TabsSecondaryPreview> {
  int _index = 0;

  static const List<String> _tabs = ['Inbox', 'Sent', 'Drafts'];

  static const List<String> _content = [
    'Inbox — your incoming messages appear here.',
    'Sent — messages you have already sent.',
    'Drafts — unfinished messages saved for later.',
  ];

  @override
  Widget build(BuildContext context) {
    final KasyColors c = context.colors;

    return Column(
      crossAxisAlignment: CrossAxisAlignment.stretch,
      mainAxisSize: MainAxisSize.min,
      children: [
        KasyTabs(
          tabs: _tabs,
          selectedIndex: _index,
          onTabSelected: (i) => setState(() => _index = i),
          variant: KasyTabsVariant.secondary,
        ),
        const SizedBox(height: KasySpacing.md),
        AnimatedSwitcher(
          duration: const Duration(milliseconds: 200),
          child: KasyCard(
            key: ValueKey(_index),
            padding: const EdgeInsets.all(KasySpacing.md),
            child: Text(
              _content[_index],
              style: context.textTheme.bodyMedium?.copyWith(
                color: c.onSurface.withValues(alpha: 0.75),
                height: 1.5,
              ),
            ),
          ),
        ),
        const SizedBox(height: KasySpacing.lg),
        // With icons
        Text(
          'WITH ICONS',
          style: context.textTheme.labelSmall?.copyWith(
            color: c.muted,
            letterSpacing: 1.2,
            fontWeight: FontWeight.w700,
          ),
        ),
        const SizedBox(height: KasySpacing.sm),
        KasyTabs.items(
          items: const [
            KasyTabItem(label: 'Home', icon: KasyIcons.home),
            KasyTabItem(label: 'Profile', icon: KasyIcons.person),
            KasyTabItem(label: 'Settings', icon: KasyIcons.settings),
          ],
          selectedIndex: 1,
          onTabSelected: (_) {},
          variant: KasyTabsVariant.secondary,
        ),
      ],
    );
  }
}

// ── Fill mode ──────────────────────────────────────────────────────────────

class _TabsFillModePreview extends StatefulWidget {
  const _TabsFillModePreview();

  @override
  State<_TabsFillModePreview> createState() => _TabsFillModePreviewState();
}

class _TabsFillModePreviewState extends State<_TabsFillModePreview> {
  int _primaryIndex = 0;
  int _secondaryIndex = 0;

  @override
  Widget build(BuildContext context) {
    final KasyColors c = context.colors;
    final TextStyle labelStyle =
        context.textTheme.labelSmall?.copyWith(
          color: c.muted,
          letterSpacing: 1.2,
          fontWeight: FontWeight.w700,
        ) ??
        const TextStyle();

    return Column(
      crossAxisAlignment: CrossAxisAlignment.stretch,
      mainAxisSize: MainAxisSize.min,
      children: [
        Text('PRIMARY + FILL', style: labelStyle),
        const SizedBox(height: KasySpacing.sm),
        KasyTabs(
          tabs: const ['Tab 1', 'Tab 2', 'Tab 3'],
          selectedIndex: _primaryIndex,
          onTabSelected: (i) => setState(() => _primaryIndex = i),
          mode: KasyTabsMode.fill,
        ),
        const SizedBox(height: KasySpacing.lg),
        Text('SECONDARY + FILL', style: labelStyle),
        const SizedBox(height: KasySpacing.sm),
        KasyTabs(
          tabs: const ['Tab 1', 'Tab 2', 'Tab 3'],
          selectedIndex: _secondaryIndex,
          onTabSelected: (i) => setState(() => _secondaryIndex = i),
          variant: KasyTabsVariant.secondary,
          mode: KasyTabsMode.fill,
        ),
        const SizedBox(height: KasySpacing.md),
        AnimatedSwitcher(
          duration: const Duration(milliseconds: 200),
          child: KasyCard(
            key: ValueKey('fill_$_secondaryIndex'),
            padding: const EdgeInsets.all(KasySpacing.md),
            child: Text(
              'Content for Tab ${_secondaryIndex + 1}',
              style: context.textTheme.bodyMedium?.copyWith(
                color: c.onSurface.withValues(alpha: 0.75),
              ),
            ),
          ),
        ),
      ],
    );
  }
}

Widget _buildSkeletonCardVariant(BuildContext context) {
  return const _SkeletonCardPreview();
}

Widget _buildSkeletonListVariant(BuildContext context) {
  return const _SkeletonListPreview();
}

Widget _buildSkeletonTextVariant(BuildContext context) {
  return const _SkeletonTextPreview();
}

Widget _buildSkeletonProfileVariant(BuildContext context) {
  return const _SkeletonProfilePreview();
}

Widget _buildSkeletonGridVariant(BuildContext context) {
  return const _SkeletonGridPreview();
}

Widget _buildAccordionDefaultVariant(BuildContext context) {
  return const _AccordionPreview(variant: KasyAccordionVariant.defaultList);
}

Widget _buildAccordionSurfaceVariant(BuildContext context) {
  return const _AccordionPreview(variant: KasyAccordionVariant.surface);
}

Widget _buildAccordionElevatedCardVariant(BuildContext context) {
  return const _AccordionPreview(variant: KasyAccordionVariant.elevatedCard);
}

Widget _buildAlertDefaultAccentVariant(BuildContext context) {
  final TextStyle labelStyle =
      context.textTheme.labelSmall?.copyWith(
        color: context.colors.muted,
        letterSpacing: 1.2,
        fontWeight: FontWeight.w700,
      ) ??
      const TextStyle();
  return Column(
    mainAxisSize: MainAxisSize.min,
    crossAxisAlignment: CrossAxisAlignment.stretch,
    children: [
      Text('DEFAULT', style: labelStyle),
      const SizedBox(height: KasySpacing.sm),
      KasyAlert(
        title: 'New features available',
        message:
            'Check out our latest updates including dark mode support and improved accessibility features.',
        leading: Icon(
          KasyIcons.error,
          size: 19,
          color: context.colors.onSurface.withValues(alpha: 0.92),
        ),
      ),
      const SizedBox(height: KasySpacing.lg),
      Text('ACCENT', style: labelStyle),
      const SizedBox(height: KasySpacing.sm),
      const KasyAlert(
        title: 'Update available',
        message:
            'A new version of the application is available. Please refresh to get the latest features and bug fixes.',
        emphasizeTitleWithTone: true,
      ),
    ],
  );
}

Widget _buildAlertSemanticVariant(BuildContext context) {
  return const Column(
    mainAxisSize: MainAxisSize.min,
    crossAxisAlignment: CrossAxisAlignment.stretch,
    children: [
      KasyAlert(
        title: 'Success',
        message:
            'Your profile information has been updated. Review the changes in your account settings.',
        tone: KasyAlertTone.success,
        emphasizeTitleWithTone: true,
      ),
      SizedBox(height: KasySpacing.sm),
      KasyAlert(
        title: 'Scheduled maintenance',
        message:
            'Our services will be unavailable on Sunday, March 15th from 2:00 AM to 6:00 AM UTC for scheduled maintenance.',
        tone: KasyAlertTone.warning,
        icon: Icons.warning_amber_rounded,
        emphasizeTitleWithTone: true,
      ),
      SizedBox(height: KasySpacing.sm),
      KasyAlert(
        title: 'Unable to connect to server',
        message:
            'Unable to connect to the server. Check your internet connection and try again.',
        tone: KasyAlertTone.danger,
        emphasizeTitleWithTone: true,
      ),
    ],
  );
}

Widget _buildAlertWithButtonsVariant(BuildContext context) {
  final TextStyle labelStyle =
      context.textTheme.labelSmall?.copyWith(
        color: context.colors.muted,
        letterSpacing: 1.2,
        fontWeight: FontWeight.w700,
      ) ??
      const TextStyle();
  return Column(
    mainAxisSize: MainAxisSize.min,
    crossAxisAlignment: CrossAxisAlignment.stretch,
    children: [
      Text('ONE ACTION', style: labelStyle),
      const SizedBox(height: KasySpacing.sm),
      KasyAlert(
        title: 'Update available',
        message:
            'A new version of the application is available. Please refresh to get the latest features and bug fixes.',
        emphasizeTitleWithTone: true,
        trailing: KasyAlertActionButton(
          label: 'Refresh',
          onPressed: () => _triggerTapFeedback(),
        ),
      ),
      const SizedBox(height: KasySpacing.lg),
      Text('TWO ACTIONS', style: labelStyle),
      const SizedBox(height: KasySpacing.sm),
      KasyAlert(
        title: 'Unable to connect to server',
        message:
            'Unable to connect to the server. Check your internet connection and try again.',
        tone: KasyAlertTone.danger,
        emphasizeTitleWithTone: true,
        trailing: KasyAlertActionButton(
          label: 'Retry',
          tone: KasyAlertTone.danger,
          onPressed: () => _triggerTapFeedback(),
        ),
      ),
      const SizedBox(height: KasySpacing.lg),
      Text('DESTRUCTIVE', style: labelStyle),
      const SizedBox(height: KasySpacing.sm),
      const KasyAlert(
        title: 'Profile updated successfully',
        tone: KasyAlertTone.success,
        emphasizeTitleWithTone: true,
        trailing: KasyAlertCircleButton(onPressed: _triggerTapFeedback),
      ),
    ],
  );
}

Widget _buildAlertLoadingVariant(BuildContext context) {
  return const _AlertLoadingPreview();
}

Widget _buildAvatarSizesVariant(BuildContext context) {
  return Row(
    mainAxisAlignment: MainAxisAlignment.spaceEvenly,
    children: [
      Column(
        mainAxisSize: MainAxisSize.min,
        children: [
          KasyAvatar.gradientFill(
            size: KasyAvatarSize.small,
            gradient: KasyAvatarGradients.blue,
            onTap: _triggerTapFeedback,
          ),
          const SizedBox(height: KasySpacing.sm),
          Text(
            'SM',
            style: context.textTheme.labelSmall?.copyWith(
              color: context.colors.muted,
              letterSpacing: 1.2,
              fontWeight: FontWeight.w700,
            ),
          ),
        ],
      ),
      Column(
        mainAxisSize: MainAxisSize.min,
        children: [
          KasyAvatar.gradientFill(
            size: KasyAvatarSize.medium,
            gradient: KasyAvatarGradients.hotPink,
            onTap: _triggerTapFeedback,
          ),
          const SizedBox(height: KasySpacing.sm),
          Text(
            'MD',
            style: context.textTheme.labelSmall?.copyWith(
              color: context.colors.muted,
              letterSpacing: 1.2,
              fontWeight: FontWeight.w700,
            ),
          ),
        ],
      ),
      Column(
        mainAxisSize: MainAxisSize.min,
        children: [
          KasyAvatar.gradientFill(
            size: KasyAvatarSize.large,
            gradient: KasyAvatarGradients.red,
            onTap: _triggerTapFeedback,
          ),
          const SizedBox(height: KasySpacing.sm),
          Text(
            'LG',
            style: context.textTheme.labelSmall?.copyWith(
              color: context.colors.muted,
              letterSpacing: 1.2,
              fontWeight: FontWeight.w700,
            ),
          ),
        ],
      ),
    ],
  );
}

Widget _buildAvatarDefaultTextFallbackVariant(BuildContext context) {
  return _avatarToneRow(
    (KasyAvatarTone tone, String letters) =>
        KasyAvatar(initials: letters, tone: tone, onTap: _triggerTapFeedback),
  );
}

Widget _buildAvatarSoftTextFallbackVariant(BuildContext context) {
  return _avatarToneRow(
    (KasyAvatarTone tone, String letters) => KasyAvatar(
      initials: letters,
      tone: tone,
      fallbackSurface: KasyAvatarFallbackSurface.soft,
      onTap: _triggerTapFeedback,
    ),
  );
}

Widget _buildAvatarDefaultIconFallbackVariant(BuildContext context) {
  return _avatarToneRow(
    (KasyAvatarTone tone, _) =>
        KasyAvatar(tone: tone, onTap: _triggerTapFeedback),
  );
}

Widget _buildAvatarSoftIconFallbackVariant(BuildContext context) {
  return _avatarToneRow(
    (KasyAvatarTone tone, _) => KasyAvatar(
      tone: tone,
      fallbackSurface: KasyAvatarFallbackSurface.soft,
      onTap: _triggerTapFeedback,
    ),
  );
}

Widget _buildAvatarCustomFallbackVariant(BuildContext context) {
  return Center(
    child: SingleChildScrollView(
      scrollDirection: Axis.horizontal,
      child: Row(
        mainAxisSize: MainAxisSize.min,
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          KasyAvatar(
            customChild: SizedBox(
              width: KasyAvatarSize.medium.diameter,
              height: KasyAvatarSize.medium.diameter,
              child: DecoratedBox(
                decoration: const BoxDecoration(
                  color: Color(0xFFF2F2F2),
                  shape: BoxShape.circle,
                ),
                child: Center(
                  child: Text(
                    '🎉',
                    style: TextStyle(
                      fontSize: KasyAvatarSize.medium.diameter * 0.42,
                    ),
                  ),
                ),
              ),
            ),
            onTap: _triggerTapFeedback,
          ),
          const SizedBox(width: KasySpacing.md),
          const KasyAvatar(
            initials: 'GB',
            backgroundGradient: KasyAvatarGradients.forest,
            onTap: _triggerTapFeedback,
          ),
          const SizedBox(width: KasySpacing.md),
          const KasyAvatar(
            tone: KasyAvatarTone.neutral,
            onTap: _triggerTapFeedback,
          ),
        ],
      ),
    ),
  );
}

Widget _buildAvatarGroupVariant(BuildContext context) {
  const double d = 48;

  Widget label(String text) => Text(
    text,
    style: context.textTheme.labelSmall?.copyWith(
      color: context.colors.muted,
      letterSpacing: 1.2,
      fontWeight: FontWeight.w700,
    ),
  );

  // Shared gradient avatars list
  final List<Widget> gradients = [
    KasyAvatar.gradientFill(size: KasyAvatarSize.small, diameter: d, showShadow: false, gradient: KasyAvatarGradients.blue),
    KasyAvatar.gradientFill(size: KasyAvatarSize.small, diameter: d, showShadow: false, gradient: KasyAvatarGradients.teal),
    KasyAvatar.gradientFill(size: KasyAvatarSize.small, diameter: d, showShadow: false, gradient: KasyAvatarGradients.orange),
    KasyAvatar.gradientFill(size: KasyAvatarSize.small, diameter: d, showShadow: false, gradient: KasyAvatarGradients.red),
    KasyAvatar.gradientFill(size: KasyAvatarSize.small, diameter: d, showShadow: false, gradient: KasyAvatarGradients.silver),
  ];

  // Shared photo avatars list
  const List<Widget> photos = [
    KasyAvatar(diameter: d, image: NetworkImage(KasyAvatarDemoPhotos.manGlasses)),
    KasyAvatar(diameter: d, image: NetworkImage(KasyAvatarDemoPhotos.womanSmile)),
    KasyAvatar(diameter: d, image: NetworkImage(KasyAvatarDemoPhotos.womanCurly)),
    KasyAvatar(diameter: d, image: NetworkImage(KasyAvatarDemoPhotos.manBeard)),
    KasyAvatar(diameter: d, image: NetworkImage(KasyAvatarDemoPhotos.manGlasses)),
  ];

  return Column(
    mainAxisSize: MainAxisSize.min,
    crossAxisAlignment: CrossAxisAlignment.stretch,
    children: [
      label('GRADIENTS + ADD'),
      const SizedBox(height: KasySpacing.sm),
      Center(
        child: KasyAvatarGroup(
          maxVisible: 5,
          extraCount: 5,
          avatars: gradients,
          onAdd: () {},
        ),
      ),
      const SizedBox(height: KasySpacing.lg),
      label('PHOTOS + ADD'),
      const SizedBox(height: KasySpacing.sm),
      Center(
        child: KasyAvatarGroup(
          maxVisible: 5,
          extraCount: 5,
          avatars: photos,
          onAdd: () {},
        ),
      ),
      const SizedBox(height: KasySpacing.lg),
      label('WITHOUT ADD'),
      const SizedBox(height: KasySpacing.sm),
      Center(
        child: KasyAvatarGroup(
          avatars: gradients,
        ),
      ),
    ],
  );
}

Widget _buildAvatarCustomStylesVariant(BuildContext context) {
  return const Center(
    child: SingleChildScrollView(
      scrollDirection: Axis.horizontal,
      child: Row(
        mainAxisSize: MainAxisSize.min,
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          KasyAvatar(
            image: NetworkImage(KasyAvatarDemoPhotos.manGlasses),
            onTap: _triggerTapFeedback,
          ),
          SizedBox(width: KasySpacing.md),
          KasyAvatar(
            image: NetworkImage(KasyAvatarDemoPhotos.womanSmile),
            shape: KasyAvatarShape.roundedSquare,
            onTap: _triggerTapFeedback,
          ),
          SizedBox(width: KasySpacing.md),
          KasyAvatar(
            image: NetworkImage(KasyAvatarDemoPhotos.womanCurly),
            showStoryRing: true,
            onTap: _triggerTapFeedback,
          ),
          SizedBox(width: KasySpacing.md),
          KasyAvatar(
            image: NetworkImage(KasyAvatarDemoPhotos.manBeard),
            status: KasyAvatarStatus.online,
            onTap: _triggerTapFeedback,
          ),
        ],
      ),
    ),
  );
}

Widget _avatarToneRow(
  KasyAvatar Function(KasyAvatarTone tone, String letters) buildOne,
) {
  const List<(KasyAvatarTone, String)> data = <(KasyAvatarTone, String)>[
    (KasyAvatarTone.blue, 'AC'),
    (KasyAvatarTone.neutral, 'DF'),
    (KasyAvatarTone.green, 'SC'),
    (KasyAvatarTone.orange, 'WR'),
    (KasyAvatarTone.red, 'DG'),
  ];
  return Center(
    child: SingleChildScrollView(
      scrollDirection: Axis.horizontal,
      child: Row(
        mainAxisSize: MainAxisSize.min,
        mainAxisAlignment: MainAxisAlignment.center,
        children: List<Widget>.generate(data.length, (int index) {
          final (KasyAvatarTone tone, String letters) = data[index];
          return Padding(
            padding: EdgeInsets.only(
              right: index < data.length - 1 ? KasySpacing.sm : 0,
            ),
            child: buildOne(tone, letters),
          );
        }),
      ),
    ),
  );
}

Widget _buildAppBarSubpageVariant(BuildContext context) {
  return const _AppBarPreview(variant: KasyAppBarStyle.subpage);
}

Widget _buildAppBarSubpageSimpleVariant(BuildContext context) {
  return const _AppBarPreview(variant: KasyAppBarStyle.subpageSimple);
}

Widget _buildAppBarSubpageActionsVariant(BuildContext context) {
  return const _AppBarPreview(variant: KasyAppBarStyle.subpageActions);
}

Widget _buildButtonSizesVariant(BuildContext context) {
  return const _ButtonSizesPreview();
}

Widget _buildButtonVariantsVariant(BuildContext context) {
  return const _ButtonVariantsPreview();
}

Widget _buildButtonDisabledStateVariant(BuildContext context) {
  return const _ButtonDisabledStatePreview();
}

Widget _buildButtonWidthAlignmentVariant(BuildContext context) {
  return const _ButtonWidthAlignmentPreview();
}

Widget _buildButtonWithIconsVariant(BuildContext context) {
  return const _ButtonWithIconsPreview();
}

Widget _buildButtonIconOnlyVariant(BuildContext context) {
  return const _ButtonIconOnlyPreview();
}

Widget _buildButtonCustomStylingVariant(BuildContext context) {
  return const _ButtonCustomStylingPreview();
}

Widget _buildButtonHoverFillVariant(BuildContext context) {
  return _ButtonHoverFillPreview();
}

Widget _buildButtonLayoutTransitionsVariant(BuildContext context) {
  return const _ButtonLayoutTransitionsPreview();
}

/// Accent used only in catalog demos (retail price); not a DS semantic token.
const Color _kCatalogRetailPriceAccent = Color(0xFFE91E63);

/// Stable Unsplash URLs for Card catalog previews (HTTPS).
abstract final class _CardCatalogPhotos {
  static const String communityA =
      'https://images.unsplash.com/photo-1513682121497-80211f36a7d3?w=600&q=80&auto=format&fit=crop';
  static const String communityB =
      'https://images.unsplash.com/photo-1517841905240-472988babdf9?w=600&q=80&auto=format&fit=crop';
  static const String eventA =
      'https://images.unsplash.com/photo-1496096265110-f83ad7f96608?w=320&q=80&auto=format&fit=crop';
  static const String eventB =
      'https://images.unsplash.com/photo-1550745165-9bc0b252726f?w=320&q=80&auto=format&fit=crop';
  static const String heroRobot =
      'https://images.unsplash.com/photo-1620712943543-bcc4688e7485?w=960&q=80&auto=format&fit=crop';
}

Widget _buildCardVariants(BuildContext context) {
  final bool dark = context.isDark;
  final Color secondaryBg = dark
      ? const Color(0xFF232325)
      : const Color(0xFFEFEFEF);
  final Color tertiaryBg = dark
      ? const Color(0xFF262728)
      : const Color(0xFFEAEAEA);

  return Column(
    mainAxisSize: MainAxisSize.min,
    crossAxisAlignment: CrossAxisAlignment.stretch,
    children: [
      const KasyCard(
        padding: EdgeInsets.all(KasySpacing.md),
        child: _CatalogTwoLineCardBody(
          title: 'Default',
          description:
              'Standard card appearance (surface-secondary). '
              'The default card variant for most use cases',
        ),
      ),
      const SizedBox(height: KasySpacing.md),
      KasyCard(
        variant: KasyCardVariant.filled,
        color: secondaryBg,
        padding: const EdgeInsets.all(KasySpacing.md),
        child: const _CatalogTwoLineCardBody(
          title: 'Secondary',
          description:
              'Medium prominence (surface-tertiary). Use to '
              'draw moderate attention.',
        ),
      ),
      const SizedBox(height: KasySpacing.md),
      KasyCard(
        variant: KasyCardVariant.filled,
        color: tertiaryBg,
        padding: const EdgeInsets.all(KasySpacing.md),
        child: const _CatalogTwoLineCardBody(
          title: 'Tertiary',
          description:
              'Higher prominence (surface-tertiary). Use for '
              'important content.',
        ),
      ),
      const SizedBox(height: KasySpacing.md),
      const KasyCard(
        variant: KasyCardVariant.outlined,
        padding: EdgeInsets.all(KasySpacing.md),
        child: _CatalogTwoLineCardBody(
          title: 'Transparent',
          description:
              'Minimal prominence with transparent background. '
              'Use for less important content or nested cards.',
        ),
      ),
    ],
  );
}

Widget _buildCardProduct(BuildContext context) {
  return KasyCard(
    padding: const EdgeInsets.all(KasySpacing.lg),
    child: Column(
      crossAxisAlignment: CrossAxisAlignment.stretch,
      mainAxisSize: MainAxisSize.min,
      children: [
        Text(
          r'$450',
          style: context.textTheme.headlineSmall?.copyWith(
            color: _kCatalogRetailPriceAccent,
            fontWeight: FontWeight.w800,
          ),
        ),
        const SizedBox(height: KasySpacing.sm),
        Text(
          'Living room Sofa',
          style: context.textTheme.titleMedium?.copyWith(
            fontWeight: FontWeight.w700,
          ),
        ),
        const SizedBox(height: KasySpacing.xs),
        Text(
          'This sofa is perfect for modern tropical spaces, baroque inspired spaces.',
          style: context.textTheme.bodySmall?.copyWith(
            color: context.colors.muted,
            height: 1.4,
          ),
        ),
        const SizedBox(height: KasySpacing.lg),
        const KasyButton(
          label: 'Buy now',
          expand: true,
          onPressed: _triggerTapFeedback,
        ),
        const SizedBox(height: KasySpacing.sm),
        KasyHover(
          onTap: _triggerTapFeedback,
          borderRadius: KasyRadius.mdBorderRadius,
          padding: const EdgeInsets.symmetric(horizontal: 18, vertical: 13),
          child: Row(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              Text(
                'Add to cart',
                style: context.textTheme.labelLarge?.copyWith(
                  fontWeight: FontWeight.w600,
                ),
              ),
              const SizedBox(width: 8),
              const Icon(KasyIcons.shoppingBag, size: 18),
            ],
          ),
        ),
      ],
    ),
  );
}

Widget _buildCardCommunity(BuildContext context) {
  return const Row(
    crossAxisAlignment: CrossAxisAlignment.start,
    children: [
      Expanded(
        child: _CatalogCommunityImageCard(
          imageUrl: _CardCatalogPhotos.communityA,
          title: 'Indie Hackers',
          subtitle: '148 members',
          handle: '@indiehackers',
          dotColor: Color(0xFFFF6B6B),
        ),
      ),
      SizedBox(width: KasySpacing.md),
      Expanded(
        child: _CatalogCommunityImageCard(
          imageUrl: _CardCatalogPhotos.communityB,
          title: 'AI Builders',
          subtitle: '362 members',
          handle: '@aibuilders',
          dotColor: Color(0xFF51CF66),
        ),
      ),
    ],
  );
}

Widget _buildCardEventList(BuildContext context) {
  return const Column(
    mainAxisSize: MainAxisSize.min,
    children: [
      _CatalogHorizontalImageCard(
        imageUrl: _CardCatalogPhotos.eventA,
        title: 'Avocado Hackathon',
        subtitle: 'Today, 6:30 PM',
      ),
      SizedBox(height: KasySpacing.md),
      _CatalogHorizontalImageCard(
        imageUrl: _CardCatalogPhotos.eventB,
        title: 'Sound Electro',
        subtitle: 'Wed, 4:30 PM',
      ),
    ],
  );
}

Widget _buildCardHero(BuildContext context) {
  final TextTheme textTheme = Theme.of(context).textTheme;
  return KasyCard(
    padding: EdgeInsets.zero,
    child: AspectRatio(
      aspectRatio: 0.95,
      child: Stack(
        fit: StackFit.expand,
        children: [
          ClipRRect(
            borderRadius: BorderRadius.circular(KasyRadius.xl),
            child: Image.network(
              _CardCatalogPhotos.heroRobot,
              fit: BoxFit.cover,
              errorBuilder: (_, _, _) =>
                  ColoredBox(color: context.colors.surfaceNeutralSoft),
            ),
          ),
          DecoratedBox(
            decoration: BoxDecoration(
              borderRadius: BorderRadius.circular(KasyRadius.xl),
              gradient: LinearGradient(
                begin: Alignment.topCenter,
                end: Alignment.bottomCenter,
                stops: const [0.0, 0.35, 1.0],
                colors: [
                  Colors.black.withValues(alpha: 0.15),
                  Colors.black.withValues(alpha: 0.0),
                  Colors.black.withValues(alpha: 0.65),
                ],
              ),
            ),
          ),
          Positioned(
            left: KasySpacing.lg,
            top: KasySpacing.lg,
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              mainAxisSize: MainAxisSize.min,
              children: [
                Text(
                  'NEO',
                  style: textTheme.labelLarge?.copyWith(
                    color: Colors.white.withValues(alpha: 0.92),
                    fontWeight: FontWeight.w600,
                    letterSpacing: 1.2,
                  ),
                ),
                const SizedBox(height: KasySpacing.xs),
                Text(
                  'Home robot',
                  style: textTheme.titleLarge?.copyWith(
                    color: Colors.white,
                    fontWeight: FontWeight.w700,
                  ),
                ),
              ],
            ),
          ),
          Positioned(
            left: KasySpacing.lg,
            right: KasySpacing.lg,
            bottom: KasySpacing.lg,
            child: Row(
              crossAxisAlignment: CrossAxisAlignment.end,
              children: [
                Expanded(
                  child: Column(
                    crossAxisAlignment: CrossAxisAlignment.start,
                    mainAxisSize: MainAxisSize.min,
                    children: [
                      Text(
                        'Available soon',
                        style: textTheme.bodyMedium?.copyWith(
                          color: Colors.white,
                          fontWeight: FontWeight.w600,
                        ),
                      ),
                      Text(
                        'Get notified',
                        style: textTheme.bodySmall?.copyWith(
                          color: Colors.white.withValues(alpha: 0.78),
                        ),
                      ),
                    ],
                  ),
                ),
                const KasyButton(
                  label: 'Notify me',
                  variant: KasyButtonVariant.inverse,
                  size: KasyButtonSize.small,
                  foregroundColor: Colors.black,
                  onPressed: _triggerTapFeedback,
                ),
              ],
            ),
          ),
        ],
      ),
    ),
  );
}

Widget _buildCardInteractiveAll(BuildContext context) {
  final TextStyle labelStyle =
      context.textTheme.labelSmall?.copyWith(
        color: context.colors.muted,
        letterSpacing: 1.2,
        fontWeight: FontWeight.w700,
      ) ??
      const TextStyle();
  return Column(
    mainAxisSize: MainAxisSize.min,
    crossAxisAlignment: CrossAxisAlignment.stretch,
    children: [
      Text('ZOOM  ·  onTap', style: labelStyle),
      const SizedBox(height: KasySpacing.sm),
      ..._buildCardInteractiveItems(context),
      const SizedBox(height: KasySpacing.lg),
      Text('FILL  ·  KasyHover', style: labelStyle),
      const SizedBox(height: KasySpacing.sm),
      const _PressableCardsPreview(),
    ],
  );
}

List<Widget> _buildCardInteractiveItems(BuildContext context) {
  return [
    KasyCard(
      padding: const EdgeInsets.all(KasySpacing.md),
      onTap: _triggerTapFeedback,
      child: Row(
        children: [
          Icon(KasyIcons.star, color: context.colors.warning, size: 20),
          const SizedBox(width: KasySpacing.smd),
          Expanded(
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                Text(
                  'Tap me',
                  style: context.textTheme.titleSmall?.copyWith(
                    fontWeight: FontWeight.w700,
                  ),
                ),
                const SizedBox(height: 2),
                Text(
                  'Cards with onTap get pressable depth feedback.',
                  style: context.textTheme.bodySmall?.copyWith(
                    color: context.colors.muted,
                  ),
                ),
              ],
            ),
          ),
          Icon(KasyIcons.chevronRight, color: context.colors.muted, size: 18),
        ],
      ),
    ),
    const SizedBox(height: KasySpacing.md),
    KasyCard(
      variant: KasyCardVariant.filled,
      padding: const EdgeInsets.all(KasySpacing.md),
      onTap: _triggerTapFeedback,
      child: Row(
        children: [
          Icon(
            KasyIcons.notification,
            color: context.colors.primary,
            size: 20,
          ),
          const SizedBox(width: KasySpacing.smd),
          Expanded(
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                Text(
                  'Filled interactive',
                  style: context.textTheme.titleSmall?.copyWith(
                    fontWeight: FontWeight.w700,
                  ),
                ),
                const SizedBox(height: 2),
                Text(
                  'Works with any variant.',
                  style: context.textTheme.bodySmall?.copyWith(
                    color: context.colors.muted,
                  ),
                ),
              ],
            ),
          ),
          Icon(KasyIcons.chevronRight, color: context.colors.muted, size: 18),
        ],
      ),
    ),
  ];
}

Widget _buildDialogBasic(BuildContext context) {
  return _previewIntrinsicLaunch(
    KasyButton(
      label: 'Basic dialog',
      variant: KasyButtonVariant.soft,
      onPressed: () {
        showKasyDialog<void>(
          context: context,
          builder: (dialogCtx) => KasyDialog(
            leadingIcon: KasyIcons.download,
            title: 'Low Disk Space',
            message:
                'You are running low on disk space. Delete unnecessary files '
                'to free up space.',
            confirmLabel: 'Confirm',
            onConfirm: () {
              Navigator.of(dialogCtx).pop();
              _triggerTapFeedback();
            },
          ),
        );
      },
    ),
  );
}

/// Catalog: outer [showKasyBottomSheet], then nested [showKasyDialog] from the
/// sheet route context.
Widget _buildDialogBlurBackdrop(BuildContext context) {
  return _previewIntrinsicLaunch(
    KasyButton(
      label: 'Dialog with blur backdrop',
      variant: KasyButtonVariant.soft,
      onPressed: () {
        showKasyBlurDialog<void>(
          context: context,
          builder: (dialogCtx) => KasyDialog(
            leadingIcon: KasyIcons.trash,
            iconTone: KasyDialogIconTone.danger,
            title: 'Delete product',
            message:
                'Are you sure you want to delete this product? '
                'This action cannot be undone.',
            showCloseButton: false,
            actions: [
              KasyButton(
                label: 'Delete',
                variant: KasyButtonVariant.destructive,
                expand: true,
                onPressed: () {
                  Navigator.of(dialogCtx).pop();
                  _triggerTapFeedback();
                },
              ),
              KasyButton(
                label: 'Cancel',
                variant: KasyButtonVariant.neutral,
                expand: true,
                onPressed: () => Navigator.of(dialogCtx).pop(),
              ),
            ],
          ),
        );
      },
    ),
  );
}

bool _isProfileEmailCandidateValid(String value) {
  final String trimmed = value.trim();
  if (trimmed.isEmpty) return false;
  final RegExp pattern = RegExp(
    r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$',
  );
  return pattern.hasMatch(trimmed);
}

class _UpdateProfileInputDialog extends StatefulWidget {
  const _UpdateProfileInputDialog();

  @override
  State<_UpdateProfileInputDialog> createState() =>
      _UpdateProfileInputDialogState();
}

class _UpdateProfileInputDialogState extends State<_UpdateProfileInputDialog> {
  late final TextEditingController _nameController;
  late final TextEditingController _emailController;
  late final FocusNode _nameFocus;
  String? _nameErrorText;
  String? _emailErrorText;

  @override
  void initState() {
    super.initState();
    _nameController = TextEditingController();
    _emailController = TextEditingController();
    _nameFocus = FocusNode();
    WidgetsBinding.instance.addPostFrameCallback((_) {
      if (!mounted) return;
      _nameFocus.requestFocus();
    });
  }

  @override
  void dispose() {
    _nameController.dispose();
    _emailController.dispose();
    _nameFocus.dispose();
    super.dispose();
  }

  void _onSubmit() {
    final String trimmedName = _nameController.text.trim();
    final bool nameOk = trimmedName.isNotEmpty;
    final bool emailOk = _isProfileEmailCandidateValid(_emailController.text);
    setState(() {
      _nameErrorText = nameOk ? null : 'Please enter your full name';
      _emailErrorText = emailOk ? null : 'Please enter a valid email address';
    });
    if (!nameOk || !emailOk) {
      return;
    }
    Navigator.of(context).pop();
    _triggerTapFeedback();
  }

  @override
  Widget build(BuildContext context) {
    return KasyDialog(
      title: 'Update Profile',
      closeAboveTitle: true,
      closeButtonStyle: KasyDialogCloseButtonStyle.filledNeutral,
      closeFilledButtonExtent: 36,
      closeFilledIconGlyphSize: 14,
      body: Column(
        crossAxisAlignment: CrossAxisAlignment.stretch,
        mainAxisSize: MainAxisSize.min,
        children: [
          KasyTextField(
            controller: _nameController,
            focusNode: _nameFocus,
            variant: KasyTextFieldVariant.secondary,
            label: 'Full Name',
            showRequiredIndicator: true,
            hint: 'Enter your name',
            errorText: _nameErrorText,
            onChanged: (_) {
              if (_nameErrorText != null) {
                setState(() => _nameErrorText = null);
              }
            },
            textInputAction: TextInputAction.next,
          ),
          const SizedBox(height: KasySpacing.md),
          KasyTextField(
            controller: _emailController,
            variant: KasyTextFieldVariant.secondary,
            label: 'Email Address',
            showRequiredIndicator: true,
            hint: 'email@example.com',
            contentType: KasyTextFieldContentType.email,
            errorText: _emailErrorText,
            onChanged: (_) {
              if (_emailErrorText != null) {
                setState(() => _emailErrorText = null);
              }
            },
            textInputAction: TextInputAction.done,
            onSubmitted: (_) => _onSubmit(),
          ),
        ],
      ),
      footer: Row(
        mainAxisAlignment: MainAxisAlignment.end,
        children: [
          KasyButton(
            label: 'Cancel',
            variant: KasyButtonVariant.ghost,
            size: KasyButtonSize.small,
            onPressed: () => Navigator.of(context).pop(),
          ),
          const SizedBox(width: KasySpacing.sm),
          KasyButton(
            label: 'Update Profile',
            size: KasyButtonSize.small,
            onPressed: _onSubmit,
          ),
        ],
      ),
    );
  }
}

Widget _buildDialogTextInput(BuildContext context) {
  return _previewIntrinsicLaunch(
    KasyButton(
      label: 'Dialog with TextField',
      variant: KasyButtonVariant.soft,
      onPressed: () {
        showKasyBlurDialog<void>(
          context: context,
          builder: (_) => const _UpdateProfileInputDialog(),
        );
      },
    ),
  );
}

const String _dialogLongContentLorem =
    'Zacchaeus was a chief tax collector living in Jericho, a prosperous city along the Jordan River. '
    'He had grown wealthy by collecting taxes on behalf of the Roman Empire, often taking more than what was required.\n\n'
    'Despite his wealth, Zacchaeus carried a deep sense of loneliness. He was despised by his own people, '
    'who considered him a traitor for serving Rome. No one invited him to their table, and no one called him a friend.\n\n'
    'One day, word spread through the city that Jesus of Nazareth was passing through Jericho. Crowds gathered along the road, '
    'eager to catch a glimpse of the man everyone was talking about. Zacchaeus wanted to see him too, '
    'but being short in stature, he could not see over the crowd. So he ran ahead and climbed a sycamore tree.\n\n'
    'When Jesus reached the spot, he looked up and said, "Zacchaeus, come down immediately. I must stay at your house today." '
    'The crowd murmured in disapproval — why would Jesus go to the home of a sinner? '
    'But Zacchaeus came down at once and welcomed Jesus with great joy.\n\n'
    'That encounter changed everything. Zacchaeus stood before Jesus and declared that he would give half of his possessions '
    'to the poor and repay four times the amount to anyone he had cheated. Jesus smiled and said, '
    '"Today salvation has come to this house." Zacchaeus had been seen, truly seen, and that was enough to transform him.';

Widget _buildDialogLongContent(BuildContext context) {
  return _previewIntrinsicLaunch(
    KasyButton(
      label: 'Dialog with long content',
      variant: KasyButtonVariant.soft,
      onPressed: () {
        showKasyScaffoldToneDialog<void>(
          context: context,
          builder: (dialogCtx) {
            final MediaQueryData mq = MediaQuery.of(dialogCtx);
            final double safeHeight = mq.size.height - mq.padding.vertical;
            final double bodyMax = (safeHeight * 0.35).clamp(
              180.0,
              safeHeight * 0.40,
            );
            return KasyDialog(
              title: 'Upload Audio',
              titleCentered: true,
              closeAboveTitle: true,
              body: KasyDialogScrollableBody(
                maxHeight: bodyMax,
                padding: const EdgeInsets.symmetric(horizontal: KasySpacing.sm),
                child: Text(
                  _dialogLongContentLorem,
                  textAlign: TextAlign.center,
                  style: Theme.of(dialogCtx).textTheme.bodyMedium?.copyWith(
                    fontSize: 14,
                    height: 1.6,
                    color: dialogCtx.colors.onSurface.withValues(alpha: 0.65),
                  ),
                ),
              ),
              footer: Row(
                mainAxisAlignment: MainAxisAlignment.center,
                children: [
                  KasyButton(
                    label: 'Agree to Terms',
                    variant: KasyButtonVariant.soft,
                    onPressed: () => Navigator.of(dialogCtx).pop(),
                  ),
                ],
              ),
            );
          },
        );
      },
    ),
  );
}

Widget _buildActionChipVariant(BuildContext context) {
  return const Wrap(
    spacing: KasySpacing.sm,
    runSpacing: KasySpacing.sm,
    children: [
      KasyChip(label: 'Default', icon: KasyIcons.star, onPressed: _noop),
      KasyChip(
        label: 'Tonal',
        variant: KasyChipVariant.tonal,
        onPressed: _noop,
      ),
    ],
  );
}

Widget _buildFilterChipVariant(BuildContext context) {
  return const _FilterChipVariantContent();
}

Widget _buildBadgeDefault(BuildContext context) {
  final TextStyle labelStyle =
      context.textTheme.labelSmall?.copyWith(
        color: context.colors.muted,
        letterSpacing: 1.2,
        fontWeight: FontWeight.w700,
      ) ??
      const TextStyle();
  return Center(
    child: Row(
      mainAxisSize: MainAxisSize.min,
      children: [
        Column(
          mainAxisSize: MainAxisSize.min,
          children: [
            KasyBadged(
              badge: const KasyBadge(text: '5'),
              child: KasyAvatar.gradientFill(
                size: KasyAvatarSize.medium,
                showShadow: false,
                gradient: KasyAvatarGradients.blue,
              ),
            ),
            const SizedBox(height: KasySpacing.sm),
            Text('UNREAD', style: labelStyle),
          ],
        ),
        const SizedBox(width: KasySpacing.md),
        Column(
          mainAxisSize: MainAxisSize.min,
          children: [
            KasyBadged(
              badge: const KasyBadge(text: 'New', tone: KasyBadgeTone.primary),
              child: KasyAvatar.gradientFill(
                size: KasyAvatarSize.medium,
                showShadow: false,
                gradient: KasyAvatarGradients.hotPink,
              ),
            ),
            const SizedBox(height: KasySpacing.sm),
            Text('COUNT', style: labelStyle),
          ],
        ),
        const SizedBox(width: KasySpacing.md),
        Column(
          mainAxisSize: MainAxisSize.min,
          children: [
            KasyBadged(
              placement: KasyBadgePlacement.bottomRight,
              badge: const KasyBadge.dot(
                tone: KasyBadgeTone.success,
                size: KasyBadgeSize.lg,
              ),
              child: KasyAvatar.gradientFill(
                size: KasyAvatarSize.medium,
                showShadow: false,
                gradient: KasyAvatarGradients.teal,
              ),
            ),
            const SizedBox(height: KasySpacing.sm),
            Text('MAX COUNT', style: labelStyle),
          ],
        ),
      ],
    ),
  );
}

Widget _buildBadgeColors(BuildContext context) {
  return const _BadgeColorsPreview();
}

Widget _buildBadgeSizes(BuildContext context) {
  return const _BadgeSizesPreview();
}

Widget _buildBadgeVariants(BuildContext context) {
  return const _BadgeVariantsPreview();
}

Widget _buildBadgePlacements(BuildContext context) {
  return const _BadgePlacementsPreview();
}

Widget _buildBadgeDot(BuildContext context) {
  return Column(
    mainAxisSize: MainAxisSize.min,
    crossAxisAlignment: CrossAxisAlignment.stretch,
    children: [
      Text(
        'TONES',
        style: context.textTheme.labelSmall?.copyWith(
          color: context.colors.muted,
          letterSpacing: 1.2,
          fontWeight: FontWeight.w700,
        ),
      ),
      const SizedBox(height: KasySpacing.sm),
      const _BadgeDotPreview(),
    ],
  );
}

Widget _buildBadgeWithContent(BuildContext context) {
  return const _BadgeWithContentPreview();
}

Widget _buildBasicTextFieldVariant(BuildContext context) {
  return const _BasicTextFieldVariantContent();
}

Widget _buildTextFieldWithLabelDescriptionVariant(BuildContext context) {
  return const _TextFieldWithLabelDescriptionVariantContent();
}

Widget _buildTextFieldStandard(BuildContext context) {
  return const _TextFieldStandardContent();
}

Widget _buildTextFieldCharacterLimit(BuildContext context) {
  final TextStyle labelStyle =
      context.textTheme.labelSmall?.copyWith(
        color: context.colors.muted,
        letterSpacing: 1.2,
        fontWeight: FontWeight.w700,
      ) ??
      const TextStyle();
  return Column(
    mainAxisSize: MainAxisSize.min,
    crossAxisAlignment: CrossAxisAlignment.stretch,
    children: [
      Text('TITLE FIELD', style: labelStyle),
      const SizedBox(height: KasySpacing.sm),
      const KasyTextField(
        label: 'Resource title',
        hint: 'Enter a short descriptive title',
        maxLength: 40,
        textInputAction: TextInputAction.next,
      ),
      const SizedBox(height: KasySpacing.lg),
      Text('DESCRIPTION FIELD', style: labelStyle),
      const SizedBox(height: KasySpacing.sm),
      const KasyTextField(
        label: 'Description',
        hint: 'Describe the resource or improvement',
        minLines: 5,
        maxLines: 5,
        maxLength: 1000,
        textInputAction: TextInputAction.newline,
      ),
    ],
  );
}

Widget _buildTextFieldVariantsVariant(BuildContext context) {
  final TextStyle labelStyle =
      context.textTheme.labelSmall?.copyWith(
        color: context.colors.muted,
        letterSpacing: 1.2,
        fontWeight: FontWeight.w700,
      ) ??
      const TextStyle();
  return Column(
    mainAxisSize: MainAxisSize.min,
    crossAxisAlignment: CrossAxisAlignment.stretch,
    children: [
      Text('PRIMARY', style: labelStyle),
      const SizedBox(height: KasySpacing.sm),
      const KasyTextField(
        label: 'Primary Variant',
        hint: 'Primary style input',
        description: 'Default variant with primary styling',
        contentType: KasyTextFieldContentType.email,
      ),
      const SizedBox(height: KasySpacing.lg),
      Text('SECONDARY', style: labelStyle),
      const SizedBox(height: KasySpacing.sm),
      const KasyTextField(
        label: 'Secondary Variant',
        hint: 'Secondary style input',
        description: 'Secondary variant for surfaces',
        variant: KasyTextFieldVariant.secondary,
        contentType: KasyTextFieldContentType.email,
      ),
    ],
  );
}

Widget _buildTextFieldStates(BuildContext context) {
  final TextStyle labelStyle =
      context.textTheme.labelSmall?.copyWith(
        color: context.colors.muted,
        letterSpacing: 1.2,
        fontWeight: FontWeight.w700,
      ) ??
      const TextStyle();
  return Column(
    mainAxisSize: MainAxisSize.min,
    crossAxisAlignment: CrossAxisAlignment.stretch,
    children: [
      Text('DEFAULT', style: labelStyle),
      const SizedBox(height: KasySpacing.sm),
      const KasyTextField(
        label: 'Default State',
        hint: 'Enter your email',
        description: 'Normal input state',
        contentType: KasyTextFieldContentType.email,
      ),
      const SizedBox(height: KasySpacing.lg),
      Text('DISABLED', style: labelStyle),
      const SizedBox(height: KasySpacing.sm),
      const KasyTextField(
        label: 'Disabled State',
        hint: 'Read only value',
        description: 'TextField is disabled and cannot be edited',
        enabled: false,
        contentType: KasyTextFieldContentType.email,
      ),
      const SizedBox(height: KasySpacing.lg),
      Text('INVALID', style: labelStyle),
      const SizedBox(height: KasySpacing.sm),
      const KasyTextField(
        label: 'Invalid State',
        hint: 'Enter your email',
        errorText: 'Please enter a valid email address',
        isInvalid: true,
        contentType: KasyTextFieldContentType.email,
      ),
    ],
  );
}

Widget _buildTextFieldWithIcon(BuildContext context) {
  return const _TextFieldWithIconContent();
}

Widget _buildTextFieldMultiline(BuildContext context) {
  return const _TextFieldMultilineContent();
}

Widget _buildTextAreaBasic(BuildContext context) {
  return const _TextAreaBasicContent();
}

Widget _buildTextAreaWithLabelDescription(BuildContext context) {
  return const _TextAreaWithLabelDescriptionContent();
}

Widget _buildTextAreaStates(BuildContext context) {
  final TextStyle labelStyle =
      context.textTheme.labelSmall?.copyWith(
        color: context.colors.muted,
        letterSpacing: 1.2,
        fontWeight: FontWeight.w700,
      ) ??
      const TextStyle();
  return Column(
    mainAxisSize: MainAxisSize.min,
    crossAxisAlignment: CrossAxisAlignment.stretch,
    children: [
      Text('DISABLED', style: labelStyle),
      const SizedBox(height: KasySpacing.sm),
      const KasyTextArea(
        label: 'Disabled State',
        hint: 'Read only value',
        description: 'Text area is disabled and cannot be edited',
        enabled: false,
      ),
      const SizedBox(height: KasySpacing.lg),
      Text('INVALID', style: labelStyle),
      const SizedBox(height: KasySpacing.sm),
      const KasyTextArea(
        label: 'Invalid State',
        hint: 'Enter your message',
        isInvalid: true,
        errorText: 'Please enter a valid message',
      ),
    ],
  );
}

Widget _buildToastDefaultVariants(BuildContext context) =>
    const _ToastVariantsPreview();

Widget _buildToastPlacementVariants(BuildContext context) =>
    const _ToastPlacementPreview();

Widget _buildToastModalPreview(BuildContext context) =>
    const _ToastModalPreview();

Widget _buildToastCustomVariants(BuildContext context) =>
    const _ToastCustomVariantsPreview();

Widget _buildToastStaticPreview(BuildContext context) =>
    const _ToastStaticPreview();

// — Toast: custom variants launcher —

class _ToastCustomVariantsPreview extends StatefulWidget {
  const _ToastCustomVariantsPreview();

  @override
  State<_ToastCustomVariantsPreview> createState() =>
      _ToastCustomVariantsPreviewState();
}

class _ToastCustomVariantsPreviewState
    extends State<_ToastCustomVariantsPreview> {
  bool _active = false;

  void _show(Widget Function(VoidCallback dismiss) builder) {
    setState(() => _active = true);
    showKasyToastWidget(
      context,
      persistent: true,
      onClose: () {
        if (mounted) setState(() => _active = false);
      },
      builder: builder,
    );
  }

  @override
  Widget build(BuildContext context) {
    return Column(
      mainAxisSize: MainAxisSize.min,
      children: [
        _previewIntrinsicLaunch(
          KasyButton(
            label: 'Achievement toast',
            variant: KasyButtonVariant.soft,
            onPressed: _active
                ? null
                : () =>
                    _show((d) => _AchievementToastCard(onClose: d)),
          ),
        ),
        const SizedBox(height: KasySpacing.sm),
        _previewIntrinsicLaunch(
          KasyButton(
            label: 'Load data toast',
            variant: KasyButtonVariant.soft,
            onPressed:
                _active ? null : () => _show((d) => _LoadDataToastCard(onClose: d)),
          ),
        ),
        const SizedBox(height: KasySpacing.sm),
        _previewIntrinsicLaunch(
          KasyButton(
            label: 'Start upload toast',
            variant: KasyButtonVariant.soft,
            onPressed:
                _active ? null : () => _show((d) => _UploadToastCard(onClose: d)),
          ),
        ),
        const SizedBox(height: KasySpacing.lg),
        _previewIntrinsicLaunch(
          KasyButton(
            label: 'Hide all toasts',
            variant: KasyButtonVariant.destructiveSoft,
            onPressed: () {
              hideAllKasyToasts();
              setState(() => _active = false);
            },
          ),
        ),
      ],
    );
  }
}

// — Achievement toast card (warm bg + floating dots) —

class _AchievementToastCard extends StatefulWidget {
  const _AchievementToastCard({required this.onClose});
  final VoidCallback onClose;

  @override
  State<_AchievementToastCard> createState() => _AchievementToastCardState();
}

class _AchievementToastCardState extends State<_AchievementToastCard>
    with TickerProviderStateMixin {
  late final List<AnimationController> _dotCtrls;
  late final List<Animation<double>> _dotAnims;

  static const List<Color> _dotColors = [
    Color(0xFFF97316),
    Color(0xFFFBBF24),
    Color(0xFFEC4899),
    Color(0xFF8B5CF6),
  ];

  static const List<Offset> _dotTargets = [
    Offset(-18, -14),
    Offset(-8, -22),
    Offset(8, -20),
    Offset(18, -12),
  ];

  @override
  void initState() {
    super.initState();
    _dotCtrls = List.generate(
      _dotColors.length,
      (i) => AnimationController(
        vsync: this,
        duration: const Duration(milliseconds: 900),
      ),
    );
    _dotAnims = _dotCtrls
        .map(
          (c) => CurvedAnimation(parent: c, curve: Curves.easeOut),
        )
        .toList();

    // Staggered start
    for (int i = 0; i < _dotCtrls.length; i++) {
      Future.delayed(Duration(milliseconds: 120 * i), () {
        if (mounted) _dotCtrls[i].repeat(reverse: true);
      });
    }

    // Auto-dismiss after 5s
    Future.delayed(const Duration(seconds: 5), () {
      if (mounted) widget.onClose();
    });
  }

  @override
  void dispose() {
    for (final c in _dotCtrls) {
      c.dispose();
    }
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return DecoratedBox(
      decoration: BoxDecoration(
        color: const Color(0xFFFEF3E7),
        borderRadius: KasyRadius.lgBorderRadius,
        border: Border.all(color: const Color(0xFFF97316).withValues(alpha: 0.4)),
        boxShadow: [
          BoxShadow(
            color: Colors.black.withValues(alpha: 0.06),
            blurRadius: 16,
            offset: const Offset(0, 10),
          ),
        ],
      ),
      child: Padding(
        padding: const EdgeInsets.symmetric(
          horizontal: KasySpacing.md,
          vertical: 14,
        ),
        child: Row(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            const Padding(
              padding: EdgeInsets.only(top: 2),
              child: Icon(
                KasyIcons.star,
                size: 24,
                color: Color(0xFFF97316),
              ),
            ),
            const SizedBox(width: KasySpacing.smd),
            Expanded(
              child: Column(
                crossAxisAlignment: CrossAxisAlignment.start,
                mainAxisSize: MainAxisSize.min,
                children: [
                  Text(
                    'New achievement!',
                    style: context.textTheme.bodySmall?.copyWith(
                      color: const Color(0xFFF97316),
                      fontWeight: FontWeight.w600,
                    ),
                  ),
                  const SizedBox(height: 2),
                  Text(
                    "You're on a 1-day study streak",
                    style: context.textTheme.titleMedium?.copyWith(
                      color: const Color(0xFF7C2D12),
                      fontWeight: FontWeight.w700,
                    ),
                  ),
                ],
              ),
            ),
            const SizedBox(width: KasySpacing.smd),
            // Close button with floating dots
            Stack(
              clipBehavior: Clip.none,
              alignment: Alignment.center,
              children: [
                for (int i = 0; i < _dotColors.length; i++)
                  AnimatedBuilder(
                    animation: _dotAnims[i],
                    builder: (context, _) {
                      final t = _dotAnims[i].value;
                      return Positioned(
                        left: _dotTargets[i].dx * t,
                        top: _dotTargets[i].dy * t,
                        child: Container(
                          width: 6,
                          height: 6,
                          decoration: BoxDecoration(
                            color: _dotColors[i].withValues(alpha: t),
                            shape: BoxShape.circle,
                          ),
                        ),
                      );
                    },
                  ),
                Padding(
                  padding: const EdgeInsets.only(top: 1),
                  child: KasyButton(
                    label: 'Close',
                    size: KasyButtonSize.small,
                    backgroundColor:
                        const Color(0xFFF97316).withValues(alpha: 0.15),
                    foregroundColor: const Color(0xFFF97316),
                    onPressed: widget.onClose,
                  ),
                ),
              ],
            ),
          ],
        ),
      ),
    );
  }
}

// — Load data toast card (spinner → checkmark) —

class _LoadDataToastCard extends StatefulWidget {
  const _LoadDataToastCard({required this.onClose});
  final VoidCallback onClose;

  @override
  State<_LoadDataToastCard> createState() => _LoadDataToastCardState();
}

class _LoadDataToastCardState extends State<_LoadDataToastCard>
    with SingleTickerProviderStateMixin {
  bool _done = false;
  late final AnimationController _spinCtrl;

  @override
  void initState() {
    super.initState();
    _spinCtrl = AnimationController(
      vsync: this,
      duration: const Duration(milliseconds: 900),
    )..repeat();

    Future.delayed(const Duration(milliseconds: 2200), () {
      if (!mounted) return;
      setState(() => _done = true);
      _spinCtrl.stop();
      Future.delayed(const Duration(milliseconds: 1400), () {
        if (mounted) widget.onClose();
      });
    });
  }

  @override
  void dispose() {
    _spinCtrl.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    final KasyColors c = context.colors;

    // Spinner: gray + thin. Icon: green checkmark on success.
    final Widget indicator = _done
        ? Icon(KasyIcons.checkCircle, size: 18, color: c.success)
        : RotationTransition(
            turns: _spinCtrl,
            child: SizedBox(
              width: 18,
              height: 18,
              child: CircularProgressIndicator(
                strokeWidth: 2,
                valueColor: AlwaysStoppedAnimation<Color>(c.muted),
              ),
            ),
          );

    return UnconstrainedBox(
      child: AnimatedSize(
        duration: const Duration(milliseconds: 180),
        curve: Curves.easeOut,
        alignment: Alignment.centerLeft,
        child: DecoratedBox(
          decoration: BoxDecoration(
            color: c.surface,
            borderRadius: KasyRadius.lgBorderRadius,
            border: Border.all(
              color: c.outline.withValues(alpha: 0.2),
            ),
          ),
          child: Padding(
            padding: const EdgeInsets.symmetric(
              horizontal: 14,
              vertical: 10,
            ),
            child: Row(
              mainAxisSize: MainAxisSize.min,
              children: [
                // Both icon and text change instantly via setState;
                // only AnimatedSize handles the smooth width expansion.
                indicator,
                const SizedBox(width: 8),
                Text(
                  _done ? 'Load success!' : 'Loading...',
                  style: context.textTheme.bodyMedium?.copyWith(
                    color: _done ? c.success : c.muted,
                    fontWeight: FontWeight.w500,
                  ),
                ),
              ],
            ),
          ),
        ),
      ),
    );
  }
}

// — Upload toast card (animated progress bar) —

class _UploadToastCard extends StatefulWidget {
  const _UploadToastCard({required this.onClose});
  final VoidCallback onClose;

  @override
  State<_UploadToastCard> createState() => _UploadToastCardState();
}

class _UploadToastCardState extends State<_UploadToastCard>
    with SingleTickerProviderStateMixin {
  late final AnimationController _progressCtrl;

  @override
  void initState() {
    super.initState();
    _progressCtrl = AnimationController(
      vsync: this,
      duration: const Duration(milliseconds: 4000),
    )..forward();

    _progressCtrl.addStatusListener((status) {
      if (status == AnimationStatus.completed && mounted) {
        Future.delayed(const Duration(milliseconds: 800), () {
          if (mounted) widget.onClose();
        });
      }
    });
  }

  @override
  void dispose() {
    _progressCtrl.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    final KasyColors c = context.colors;
    final bool isDark = context.isDark;

    return DecoratedBox(
      decoration: BoxDecoration(
        color: c.surface,
        borderRadius: KasyRadius.lgBorderRadius,
        border: Border.all(
          color: c.outline.withValues(alpha: isDark ? 0.22 : 0.28),
        ),
        boxShadow: [
          BoxShadow(
            color: Colors.black.withValues(alpha: isDark ? 0.20 : 0.06),
            blurRadius: 16,
            offset: const Offset(0, 10),
          ),
        ],
      ),
      child: Padding(
        padding: const EdgeInsets.symmetric(
          horizontal: KasySpacing.md,
          vertical: 14,
        ),
        child: Row(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            AnimatedBuilder(
              animation: _progressCtrl,
              builder: (context, _) {
                // Transition from primary → success in the last 10% of progress
                final colorT =
                    ((_progressCtrl.value - 0.9) / 0.1).clamp(0.0, 1.0);
                final iconColor =
                    Color.lerp(c.primary, c.success, colorT)!;
                return Padding(
                  padding: const EdgeInsets.only(top: 2),
                  child: Icon(KasyIcons.arrowUp, size: 24, color: iconColor),
                );
              },
            ),
            const SizedBox(width: KasySpacing.smd),
            Expanded(
              child: Column(
                crossAxisAlignment: CrossAxisAlignment.start,
                mainAxisSize: MainAxisSize.min,
                children: [
                  AnimatedBuilder(
                    animation: _progressCtrl,
                    builder: (context, _) {
                      final pct = (_progressCtrl.value * 100).round();
                      final bool done = _progressCtrl.value >= 1.0;
                      return Text(
                        done ? 'Upload complete!' : 'Uploading... $pct%',
                        style: context.textTheme.titleMedium?.copyWith(
                          color: done ? c.success : c.onSurface,
                          fontWeight: FontWeight.w700,
                        ),
                      );
                    },
                  ),
                  const SizedBox(height: 8),
                  AnimatedBuilder(
                    animation: _progressCtrl,
                    builder: (context, _) {
                      final bool done = _progressCtrl.value >= 1.0;
                      return ClipRRect(
                        borderRadius: BorderRadius.circular(100),
                        child: LinearProgressIndicator(
                          value: _progressCtrl.value,
                          minHeight: 5,
                          backgroundColor:
                              c.outline.withValues(alpha: 0.2),
                          valueColor: AlwaysStoppedAnimation<Color>(
                            done ? c.success : c.primary,
                          ),
                        ),
                      );
                    },
                  ),
                ],
              ),
            ),
          ],
        ),
      ),
    );
  }
}

// — Toast: interactive launcher —

class _ToastVariantsPreview extends StatelessWidget {
  const _ToastVariantsPreview();

  @override
  Widget build(BuildContext context) {
    return Column(
      mainAxisSize: MainAxisSize.min,
      children: [
        _toastBtn(
          context,
          label: 'Default toast',
          onTap: () => showKasyToast(
            context,
            title: 'Join a team',
            message:
                'Junior Garcia sent you an invitation to join HeroUI team!',
            icon: _logoChip(context),
          ),
        ),
        const SizedBox(height: KasySpacing.sm),
        _toastBtn(
          context,
          label: 'Accent toast',
          onTap: () => showKasyToast(
            context,
            title: 'You have 2 credits left',
            message: 'Get a paid plan for more credits',
            tone: KasyToastTone.accent,
          ),
        ),
        const SizedBox(height: KasySpacing.sm),
        _toastBtn(
          context,
          label: 'Success toast',
          onTap: () => showKasyToast(
            context,
            title: 'You have upgraded your plan',
            message: 'You can continue using Kasy Chat',
            tone: KasyToastTone.success,
          ),
        ),
        const SizedBox(height: KasySpacing.sm),
        _toastBtn(
          context,
          label: 'Warning toast',
          onTap: () => showKasyToast(
            context,
            title: 'You have no credits left',
            message: 'Upgrade to a paid plan to continue',
            tone: KasyToastTone.warning,
          ),
        ),
        const SizedBox(height: KasySpacing.sm),
        _toastBtn(
          context,
          label: 'Danger toast',
          onTap: () => showKasyToast(
            context,
            title: 'Storage is full',
            message:
                'Remove files to release space. Adding more content may cause issues.',
            tone: KasyToastTone.danger,
          ),
        ),
        const SizedBox(height: KasySpacing.lg),
        _previewIntrinsicLaunch(
          const KasyButton(
            label: 'Hide all toasts',
            variant: KasyButtonVariant.destructiveSoft,
            onPressed: hideAllKasyToasts,
          ),
        ),
      ],
    );
  }

  Widget _toastBtn(
    BuildContext context, {
    required String label,
    required VoidCallback onTap,
  }) {
    return _previewIntrinsicLaunch(
      KasyButton(
        label: label,
        variant: KasyButtonVariant.soft,
        onPressed: onTap,
      ),
    );
  }

  Widget _logoChip(BuildContext context) => Container(
        width: 26,
        height: 26,
        decoration: BoxDecoration(
          color: context.colors.onSurface,
          borderRadius: BorderRadius.circular(KasyRadius.xs),
        ),
        child: Icon(KasyIcons.widgets, size: 15, color: context.colors.surface),
      );
}

// — Toast: static cards preview (all 5 tones, close buttons functional) —

class _ToastStaticPreview extends StatefulWidget {
  const _ToastStaticPreview();

  @override
  State<_ToastStaticPreview> createState() => _ToastStaticPreviewState();
}

class _ToastStaticPreviewState extends State<_ToastStaticPreview> {
  final Set<int> _dismissed = {};

  Widget _logoChip() => Builder(
        builder: (ctx) => Container(
          width: 26,
          height: 26,
          decoration: BoxDecoration(
            color: ctx.colors.onSurface,
            borderRadius: BorderRadius.circular(KasyRadius.xs),
          ),
          child:
              Icon(KasyIcons.widgets, size: 15, color: ctx.colors.surface),
        ),
      );

  @override
  Widget build(BuildContext context) {
    final items = <(int, KasyToast)>[
      (
        0,
        KasyToast(
          title: 'Join a team',
          message:
              'Junior Garcia sent you an invitation to join HeroUI team!',
          icon: _logoChip(),
          onClose: () => setState(() => _dismissed.add(0)),
        ),
      ),
      (
        1,
        KasyToast(
          title: 'You have 2 credits left',
          message: 'Get a paid plan for more credits',
          tone: KasyToastTone.accent,
          onClose: () => setState(() => _dismissed.add(1)),
        ),
      ),
      (
        2,
        KasyToast(
          title: 'You have upgraded your plan',
          message: 'You can continue using Kasy Chat',
          tone: KasyToastTone.success,
          onClose: () => setState(() => _dismissed.add(2)),
        ),
      ),
      (
        3,
        KasyToast(
          title: 'You have no credits left',
          message: 'Upgrade to a paid plan to continue',
          tone: KasyToastTone.warning,
          onClose: () => setState(() => _dismissed.add(3)),
        ),
      ),
      (
        4,
        KasyToast(
          title: 'Storage is full',
          message:
              "Remove files to release space. I'm adding more text as usual but it's okay I guess I just want to see how it looks with a lot of information",
          tone: KasyToastTone.danger,
          onClose: () => setState(() => _dismissed.add(4)),
        ),
      ),
    ];

    final visible = items.where((e) => !_dismissed.contains(e.$1)).toList();

    if (visible.isEmpty) {
      return Center(
        child: Column(
          mainAxisSize: MainAxisSize.min,
          children: [
            Icon(KasyIcons.checkCircle,
                size: 32, color: context.colors.success),
            const SizedBox(height: KasySpacing.sm),
            Text(
              'All dismissed',
              style: context.textTheme.bodySmall
                  ?.copyWith(color: context.colors.muted),
            ),
            const SizedBox(height: KasySpacing.md),
            KasyButton(
              label: 'Reset',
              variant: KasyButtonVariant.soft,
              onPressed: () => setState(() => _dismissed.clear()),
            ),
          ],
        ),
      );
    }

    return Column(
      mainAxisSize: MainAxisSize.min,
      children: [
        for (final (idx, toast) in visible) ...[
          if (idx != visible.first.$1) const SizedBox(height: KasySpacing.sm),
          AnimatedSize(
            duration: const Duration(milliseconds: 220),
            curve: Curves.easeOut,
            child: toast,
          ),
        ],
      ],
    );
  }
}

// — Toast: placement variants (top / bottom) —

class _ToastPlacementPreview extends StatelessWidget {
  const _ToastPlacementPreview();

  @override
  Widget build(BuildContext context) {
    return Column(
      mainAxisSize: MainAxisSize.min,
      children: [
        _previewIntrinsicLaunch(
          KasyButton(
            label: 'Top toast',
            variant: KasyButtonVariant.soft,
            onPressed: () => showKasyToast(
              context,
              title: 'Top notification',
              message: 'Slide in from the top of the screen',
              tone: KasyToastTone.accent,
            ),
          ),
        ),
        const SizedBox(height: KasySpacing.sm),
        _previewIntrinsicLaunch(
          KasyButton(
            label: 'Bottom toast',
            variant: KasyButtonVariant.soft,
            onPressed: () => showKasyToast(
              context,
              title: 'Bottom notification',
              message: 'Slide in from the bottom of the screen',
              tone: KasyToastTone.success,
              placement: KasyToastPlacement.bottom,
            ),
          ),
        ),
        const SizedBox(height: KasySpacing.lg),
        _previewIntrinsicLaunch(
          const KasyButton(
            label: 'Hide all toasts',
            variant: KasyButtonVariant.destructiveSoft,
            onPressed: hideAllKasyToasts,
          ),
        ),
      ],
    );
  }
}

// — Toast: from native modal —

class _ToastModalPreview extends StatelessWidget {
  const _ToastModalPreview();

  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.symmetric(
        horizontal: KasySpacing.pageHorizontalGutter,
      ),
      child: _previewIntrinsicLaunch(
        KasyButton(
          label: 'Open page sheet',
          variant: KasyButtonVariant.soft,
          onPressed: () {
            _triggerTapFeedback();
            showKasyBottomSheet<void>(
              context: context,
              isScrollControlled: true,
              builder: (sheetCtx) => FractionallySizedBox(
                heightFactor: 0.92,
                child: ClipRRect(
                  borderRadius: const BorderRadius.vertical(
                    top: Radius.circular(KasyRadius.xl),
                  ),
                  child: ColoredBox(
                    color: sheetCtx.colors.background,
                    child: Column(
                      crossAxisAlignment: CrossAxisAlignment.stretch,
                      children: [
                        const KasyAppBar(
                          title: 'Toast from page sheet',
                          style: KasyAppBarStyle.rootTab,
                          useSafeArea: false,
                          toolbarHeight: 48,
                          topInset: 10,
                        ),
                        Padding(
                          padding: const EdgeInsets.symmetric(
                            horizontal: KasySpacing.lg,
                            vertical: KasySpacing.lg,
                          ),
                          child: Column(
                            crossAxisAlignment: CrossAxisAlignment.start,
                            children: [
                              Text(
                                'Toasts aparecem acima do page sheet, sobre qualquer camada de navegacao.',
                                style: sheetCtx.textTheme.bodyMedium?.copyWith(
                                  color: sheetCtx.colors.onSurface
                                      .withValues(alpha: 0.6),
                                  height: 1.5,
                                ),
                              ),
                              const SizedBox(height: KasySpacing.lg),
                              _previewIntrinsicLaunch(
                                KasyButton(
                                  label: 'Show toast',
                                  variant: KasyButtonVariant.soft,
                                  onPressed: () => showKasyToast(
                                    sheetCtx,
                                    title: 'Toast from page sheet',
                                    message:
                                        'Appears above the sheet as expected',
                                    tone: KasyToastTone.success,
                                  ),
                                ),
                              ),
                              const SizedBox(height: KasySpacing.sm),
                              _previewIntrinsicLaunch(
                                const KasyButton(
                                  label: 'Hide all toasts',
                                  variant: KasyButtonVariant.destructiveSoft,
                                  onPressed: hideAllKasyToasts,
                                ),
                              ),
                            ],
                          ),
                        ),
                      ],
                    ),
                  ),
                ),
              ),
            );
          },
        ),
      ),
    );
  }
}

class _AccordionPreview extends StatefulWidget {
  final KasyAccordionVariant variant;

  const _AccordionPreview({required this.variant});

  @override
  State<_AccordionPreview> createState() => _AccordionPreviewState();
}

class _AccordionPreviewState extends State<_AccordionPreview> {
  late Set<int> _expandedIndices;

  @override
  void initState() {
    super.initState();
    _expandedIndices = widget.variant == KasyAccordionVariant.elevatedCard
        ? <int>{0, 1}
        : <int>{1};
  }

  @override
  void didUpdateWidget(covariant _AccordionPreview oldWidget) {
    super.didUpdateWidget(oldWidget);
    if (oldWidget.variant != widget.variant) {
      _expandedIndices = widget.variant == KasyAccordionVariant.elevatedCard
          ? <int>{0, 1}
          : <int>{1};
    }
  }

  @override
  Widget build(BuildContext context) {
    if (widget.variant == KasyAccordionVariant.elevatedCard) {
      return KasyAccordion.multiple(
        surfaceRadius: 28,
        items: _kAccordionElevatedItems,
        expandedIndices: _expandedIndices,
        onExpandedIndicesChanged: (Set<int> next) {
          setState(() => _expandedIndices = next);
          KasyHaptics.selection(context);
        },
      );
    }
    return KasyAccordion.single(
      variant: widget.variant,
      surfaceRadius: 22,
      items: _kAccordionItems,
      expandedIndex: _expandedIndices.isEmpty ? -1 : _expandedIndices.first,
      onExpandedIndexChanged: (int index) {
        setState(() {
          _expandedIndices = index < 0 ? <int>{} : <int>{index};
        });
        KasyHaptics.selection(context);
      },
    );
  }
}

class _AppBarPreview extends StatelessWidget {
  final KasyAppBarStyle variant;

  const _AppBarPreview({required this.variant});

  @override
  Widget build(BuildContext context) {
    final Widget trailing = KasyChromeOrbIconButton(
      icon: Icons.more_vert,
      iconSize: 20,
      foregroundColor: context.colors.onSurface,
      fillColor: kasyChromeOrbFillColor(context),
      tooltip: 'More',
      onPressed: () {},
    );
    return DecoratedBox(
      decoration: BoxDecoration(
        color: context.colors.surface,
        borderRadius: BorderRadius.circular(KasyRadius.xl),
        border: Border.all(
          color: context.colors.outline.withValues(alpha: 0.3),
        ),
        boxShadow: [KasyShadows.component(context)],
      ),
      child: ClipRRect(
        borderRadius: BorderRadius.circular(KasyRadius.xl),
        child: SizedBox(
          height: 236,
          child: Stack(
            fit: StackFit.expand,
            children: [
              const _AppBarMockBody(),
              Positioned(
                top: 0,
                left: 0,
                right: 0,
                child: KasyAppBar(
                  useSafeArea: false,
                  title: 'Preview',
                  style: variant,
                  onBack: () {},
                  trailing: variant == KasyAppBarStyle.subpageActions
                      ? trailing
                      : null,
                ),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

class _AppBarMockBody extends StatelessWidget {
  const _AppBarMockBody();

  @override
  Widget build(BuildContext context) {
    return const Padding(
      padding: EdgeInsets.fromLTRB(
        KasySpacing.md,
        92,
        KasySpacing.md,
        KasySpacing.md,
      ),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.stretch,
        children: <Widget>[
          _AppBarBodyLine(widthFactor: 0.58),
          SizedBox(height: KasySpacing.sm),
          _AppBarBodyLine(widthFactor: 0.84),
          SizedBox(height: KasySpacing.sm),
          _AppBarBodyLine(widthFactor: 0.72),
          Spacer(),
          _AppBarBodyLine(widthFactor: 0.48),
        ],
      ),
    );
  }
}

class _AppBarBodyLine extends StatelessWidget {
  final double widthFactor;

  const _AppBarBodyLine({required this.widthFactor});

  @override
  Widget build(BuildContext context) {
    return FractionallySizedBox(
      widthFactor: widthFactor,
      alignment: Alignment.centerLeft,
      child: DecoratedBox(
        decoration: BoxDecoration(
          color: context.colors.outline.withValues(alpha: 0.24),
          borderRadius: BorderRadius.circular(KasyRadius.full),
        ),
        child: const SizedBox(height: 10),
      ),
    );
  }
}

class _AlertLoadingPreview extends StatelessWidget {
  const _AlertLoadingPreview();

  @override
  Widget build(BuildContext context) {
    return const KasyAlert(
      title: 'Processing your request',
      message:
          'Please wait while we sync your data. This may take a few moments.',
      emphasizeTitleWithTone: true,
      isLoading: true,
    );
  }
}

class _ButtonSizesPreview extends StatelessWidget {
  const _ButtonSizesPreview();

  @override
  Widget build(BuildContext context) {
    return const Column(
      children: [
        KasyButton(
          label: 'Small Button',
          onPressed: _noop,
          size: KasyButtonSize.small,
          expand: true,
        ),
        SizedBox(height: KasySpacing.md),
        KasyButton(label: 'Medium Button', onPressed: _noop, expand: true),
        SizedBox(height: KasySpacing.md),
        KasyButton(
          label: 'Large Button',
          onPressed: _noop,
          size: KasyButtonSize.large,
          expand: true,
        ),
      ],
    );
  }
}

class _ButtonVariantsPreview extends StatelessWidget {
  const _ButtonVariantsPreview();

  @override
  Widget build(BuildContext context) {
    return const Column(
      children: [
        KasyButton(label: 'Primary', onPressed: _noop, expand: true),
        SizedBox(height: KasySpacing.md),
        KasyButton(
          label: 'Secondary',
          onPressed: _noop,
          variant: KasyButtonVariant.secondary,
          expand: true,
        ),
        SizedBox(height: KasySpacing.md),
        KasyButton(
          label: 'Tertiary',
          onPressed: _noop,
          variant: KasyButtonVariant.tertiary,
          expand: true,
        ),
        SizedBox(height: KasySpacing.md),
        KasyButton(
          label: 'Outline',
          onPressed: _noop,
          variant: KasyButtonVariant.outline,
          expand: true,
        ),
        SizedBox(height: KasySpacing.md),
        KasyButton(
          label: 'Ghost',
          onPressed: _noop,
          variant: KasyButtonVariant.ghost,
          expand: true,
        ),
        SizedBox(height: KasySpacing.md),
        KasyButton(
          label: 'Danger',
          onPressed: _noop,
          variant: KasyButtonVariant.destructive,
          expand: true,
        ),
        SizedBox(height: KasySpacing.md),
        KasyButton(
          label: 'Danger Soft',
          onPressed: _noop,
          variant: KasyButtonVariant.destructiveSoft,
          expand: true,
        ),
      ],
    );
  }
}

class _ButtonDisabledStatePreview extends StatelessWidget {
  const _ButtonDisabledStatePreview();

  @override
  Widget build(BuildContext context) {
    return const Column(
      children: [
        KasyButton(
          label: 'Loading',
          onPressed: null,
          isLoading: true,
          expand: true,
        ),
        SizedBox(height: KasySpacing.md),
        KasyButton(
          label: 'Loading',
          onPressed: null,
          isLoading: true,
          variant: KasyButtonVariant.neutral,
          expand: true,
        ),
        SizedBox(height: KasySpacing.md),
        KasyButton(
          label: 'Access Denied',
          onPressed: null,
          icon: KasyIcons.info,
          variant: KasyButtonVariant.neutral,
          expand: true,
        ),
      ],
    );
  }
}

class _ButtonWidthAlignmentPreview extends StatelessWidget {
  const _ButtonWidthAlignmentPreview();

  @override
  Widget build(BuildContext context) {
    return const Column(
      children: [
        KasyButton(label: 'Full Width Button', onPressed: _noop, expand: true),
        SizedBox(height: KasySpacing.lg),
        Align(
          alignment: Alignment.centerLeft,
          child: KasyButton(
            label: 'Start',
            onPressed: _noop,
            variant: KasyButtonVariant.soft,
            size: KasyButtonSize.small,
            width: 116,
          ),
        ),
        SizedBox(height: KasySpacing.md),
        Align(
          child: KasyButton(
            label: 'Center',
            onPressed: _noop,
            variant: KasyButtonVariant.soft,
            size: KasyButtonSize.small,
            width: 132,
          ),
        ),
        SizedBox(height: KasySpacing.md),
        Align(
          alignment: Alignment.centerRight,
          child: KasyButton(
            label: 'End',
            onPressed: _noop,
            variant: KasyButtonVariant.soft,
            size: KasyButtonSize.small,
            width: 108,
          ),
        ),
      ],
    );
  }
}

class _ButtonWithIconsPreview extends StatelessWidget {
  const _ButtonWithIconsPreview();

  @override
  Widget build(BuildContext context) {
    return const Column(
      children: [
        KasyButton(
          label: 'Add Member',
          onPressed: _noop,
          icon: KasyIcons.add,
          expand: true,
        ),
        SizedBox(height: KasySpacing.md),
        KasyButton(
          label: 'Download',
          onPressed: _noop,
          icon: KasyIcons.download,
          iconAlignment: KasyButtonIconAlignment.trailing,
          variant: KasyButtonVariant.soft,
          expand: true,
        ),
        SizedBox(height: KasySpacing.md),
        KasyButton(
          label: 'Delete',
          onPressed: _noop,
          icon: KasyIcons.trash,
          variant: KasyButtonVariant.destructive,
          expand: true,
        ),
      ],
    );
  }
}

class _ButtonIconOnlyPreview extends StatelessWidget {
  const _ButtonIconOnlyPreview();

  @override
  Widget build(BuildContext context) {
    return const Padding(
      padding: EdgeInsets.only(top: 4, bottom: 16),
      child: Row(
        mainAxisAlignment: MainAxisAlignment.center,
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          Padding(
            padding: EdgeInsets.zero,
            child: KasyButton.iconOnly(
              icon: KasyIcons.share,
              onPressed: _noop,
              size: KasyButtonSize.small,
              hapticFeedbackEnabled: false,
              semanticLabel: 'Share',
            ),
          ),
          SizedBox(width: KasySpacing.md),
          Padding(
            padding: EdgeInsets.only(top: 14),
            child: KasyButton.iconOnly(
              icon: KasyIcons.favoriteFilled,
              onPressed: _noop,
              variant: KasyButtonVariant.soft,
              foregroundColor: KasyColors.semanticError,
              hapticFeedbackEnabled: false,
              semanticLabel: 'Favorite',
            ),
          ),
          SizedBox(width: KasySpacing.md),
          Padding(
            padding: EdgeInsets.only(top: 26),
            child: KasyButton.iconOnly(
              icon: KasyIcons.trash,
              onPressed: _noop,
              variant: KasyButtonVariant.destructive,
              size: KasyButtonSize.large,
              hapticFeedbackEnabled: false,
              semanticLabel: 'Delete',
            ),
          ),
        ],
      ),
    );
  }
}

class _ButtonCustomStylingPreview extends StatelessWidget {
  const _ButtonCustomStylingPreview();

  @override
  Widget build(BuildContext context) {
    final bool isDark = context.isDark;
    return Column(
      children: [
        const KasyButton(
          label: 'Custom Avocado',
          onPressed: _noop,
          backgroundColor: Color(0xFF7ACA45),
          foregroundColor: Colors.white,
          expand: true,
        ),
        const SizedBox(height: KasySpacing.md),
        const KasyButton(
          label: 'Gradient',
          onPressed: _noop,
          backgroundGradient: LinearGradient(
            begin: Alignment.topLeft,
            end: Alignment.bottomRight,
            colors: <Color>[Color(0xFF94C9FF), Color(0xFF1E56A0)],
          ),
          foregroundColor: Colors.white,
          expand: true,
        ),
        const SizedBox(height: KasySpacing.md),
        const KasyButton(
          label: 'Pill Radius',
          onPressed: _noop,
          borderRadius: BorderRadius.all(Radius.circular(KasyRadius.full)),
          expand: true,
        ),
        const SizedBox(height: KasySpacing.md),
        KasyButton(
          label: 'Add to Cart',
          onPressed: _noop,
          icon: KasyIcons.shoppingBag,
          backgroundColor: isDark ? Colors.white : const Color(0xFF121212),
          foregroundColor: isDark ? Colors.black : Colors.white,
          borderColor: isDark
              ? const Color(0x1F000000)
              : const Color(0x0FFFFFFF),
          outlineWidth: 0.38,
          borderRadius: const BorderRadius.all(Radius.circular(6)),
          expand: true,
        ),
      ],
    );
  }
}

class _ButtonHoverFillPreview extends StatelessWidget {
  static const BorderRadius _pill =
      BorderRadius.all(Radius.circular(KasyRadius.full));

  @override
  Widget build(BuildContext context) {
    final labelStyle = context.textTheme.labelSmall?.copyWith(
      color: context.colors.muted,
      letterSpacing: 1.2,
      fontWeight: FontWeight.w700,
    );
    return Column(
      crossAxisAlignment: CrossAxisAlignment.stretch,
      children: [
        Text('FILL', style: labelStyle),
        const SizedBox(height: KasySpacing.sm),
        KasyButton(
          label: 'View plans',
          icon: KasyIcons.payment,
          variant: KasyButtonVariant.outline,
          pressEffect: KasyButtonPressEffect.fill,
          backgroundColor: context.colors.surface,
          borderRadius: _pill,
          expand: true,
          onPressed: _noop,
        ),
        const SizedBox(height: KasySpacing.sm),
        const KasyButton(
          label: 'Add to list',
          icon: KasyIcons.add,
          variant: KasyButtonVariant.outline,
          pressEffect: KasyButtonPressEffect.fill,
          expand: true,
          onPressed: _noop,
        ),
        const SizedBox(height: KasySpacing.lg),
        Text('ZOOM + FILL', style: labelStyle),
        const SizedBox(height: KasySpacing.sm),
        const KasyButton(
          label: 'Subscribe now',
          icon: KasyIcons.star,
          pressEffect: KasyButtonPressEffect.both,
          borderRadius: _pill,
          expand: true,
          onPressed: _noop,
        ),
        const SizedBox(height: KasySpacing.sm),
        const KasyButton(
          label: 'Add to list',
          icon: KasyIcons.add,
          variant: KasyButtonVariant.outline,
          pressEffect: KasyButtonPressEffect.both,
          expand: true,
          onPressed: _noop,
        ),
      ],
    );
  }
}

class _ButtonLayoutTransitionsPreview extends StatefulWidget {
  const _ButtonLayoutTransitionsPreview();

  @override
  State<_ButtonLayoutTransitionsPreview> createState() =>
      _ButtonLayoutTransitionsPreviewState();
}

class _ButtonLayoutTransitionsPreviewState
    extends State<_ButtonLayoutTransitionsPreview> {
  bool _isLoading = false;
  static const String _label = 'Download now';

  Future<void> _onDownloadPressed() async {
    if (_isLoading) {
      return;
    }
    setState(() => _isLoading = true);
    try {
      // Demo fallback only. In production, await the real work Future.
      await Future<void>.delayed(const Duration(seconds: 2));
    } finally {
      if (mounted) {
        setState(() => _isLoading = false);
      }
    }
  }

  @override
  Widget build(BuildContext context) {
    final TextStyle textStyle =
        context.textTheme.labelLarge?.copyWith(
          fontWeight: FontWeight.w600,
          fontSize: 14,
          height: 1.05,
        ) ??
        const TextStyle(
          fontWeight: FontWeight.w600,
          fontSize: 14,
          height: 1.05,
        );
    final TextPainter textPainter = TextPainter(
      text: TextSpan(text: _label, style: textStyle),
      maxLines: 1,
      textDirection: Directionality.of(context),
    )..layout();
    final double buttonWidth = textPainter.width + (18 * 2);

    return Center(
      child: KasyButton(
        label: _label,
        onPressed: _onDownloadPressed,
        isLoading: _isLoading,
        width: buttonWidth,
        borderRadius: BorderRadius.circular(KasyRadius.full),
        loadingBehavior: KasyButtonLoadingBehavior.shrinkToCircle,
        semanticLabel: _label,
      ),
    );
  }
}

class _CatalogTwoLineCardBody extends StatelessWidget {
  final String title;
  final String description;

  const _CatalogTwoLineCardBody({
    required this.title,
    required this.description,
  });

  @override
  Widget build(BuildContext context) {
    return Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        Text(
          title,
          style: context.textTheme.titleSmall?.copyWith(
            fontWeight: FontWeight.w700,
          ),
        ),
        const SizedBox(height: KasySpacing.xs),
        Text(
          description,
          style: context.textTheme.bodySmall?.copyWith(
            color: context.colors.muted,
            height: 1.4,
          ),
        ),
      ],
    );
  }
}

class _CatalogCommunityImageCard extends StatelessWidget {
  final String imageUrl;
  final String title;
  final String subtitle;
  final String handle;
  final Color dotColor;

  const _CatalogCommunityImageCard({
    required this.imageUrl,
    required this.title,
    required this.subtitle,
    required this.handle,
    required this.dotColor,
  });

  @override
  Widget build(BuildContext context) {
    return KasyCard(
      padding: const EdgeInsets.all(KasySpacing.smd),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        mainAxisSize: MainAxisSize.min,
        children: [
          ClipRRect(
            borderRadius: BorderRadius.circular(KasyRadius.md),
            child: SizedBox(
              width: 64,
              height: 64,
              child: Image.network(
                imageUrl,
                fit: BoxFit.cover,
                errorBuilder: (_, _, _) =>
                    ColoredBox(color: context.colors.surfaceNeutralSoft),
              ),
            ),
          ),
          const SizedBox(height: KasySpacing.smd),
          Text(
            title,
            style: context.textTheme.titleMedium?.copyWith(
              fontWeight: FontWeight.w700,
            ),
          ),
          const SizedBox(height: 2),
          Text(
            subtitle,
            style: context.textTheme.bodyMedium?.copyWith(
              color: context.colors.muted,
            ),
          ),
          const SizedBox(height: KasySpacing.smd),
          Row(
            children: [
              Container(
                width: 10,
                height: 10,
                decoration: BoxDecoration(
                  shape: BoxShape.circle,
                  color: dotColor,
                ),
              ),
              const SizedBox(width: 6),
              Expanded(
                child: Text(
                  handle,
                  style: context.textTheme.labelMedium?.copyWith(
                    color: context.colors.muted,
                    fontWeight: FontWeight.w500,
                  ),
                  overflow: TextOverflow.ellipsis,
                ),
              ),
            ],
          ),
        ],
      ),
    );
  }
}

class _CatalogHorizontalImageCard extends StatelessWidget {
  final String imageUrl;
  final String title;
  final String subtitle;

  const _CatalogHorizontalImageCard({
    required this.imageUrl,
    required this.title,
    required this.subtitle,
  });

  @override
  Widget build(BuildContext context) {
    const double imageSize = 84;
    return KasyCard(
      padding: const EdgeInsets.all(KasySpacing.smd),
      child: Row(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          ClipRRect(
            borderRadius: BorderRadius.circular(KasyRadius.md),
            child: SizedBox(
              width: imageSize,
              height: imageSize,
              child: Image.network(
                imageUrl,
                fit: BoxFit.cover,
                errorBuilder: (_, _, _) =>
                    ColoredBox(color: context.colors.surfaceNeutralSoft),
              ),
            ),
          ),
          const SizedBox(width: KasySpacing.smd),
          Expanded(
            child: SizedBox(
              height: imageSize,
              child: Column(
                crossAxisAlignment: CrossAxisAlignment.start,
                mainAxisAlignment: MainAxisAlignment.spaceBetween,
                children: [
                  Column(
                    crossAxisAlignment: CrossAxisAlignment.start,
                    children: [
                      Text(
                        title,
                        style: context.textTheme.titleSmall?.copyWith(
                          fontWeight: FontWeight.w700,
                        ),
                        maxLines: 1,
                        overflow: TextOverflow.ellipsis,
                      ),
                      const SizedBox(height: 2),
                      Text(
                        subtitle,
                        style: context.textTheme.bodySmall?.copyWith(
                          color: context.colors.muted,
                        ),
                      ),
                    ],
                  ),
                  KasyHover(
                    onTap: _triggerTapFeedback,
                    borderRadius: KasyRadius.smBorderRadius,
                    padding: const EdgeInsets.symmetric(
                      vertical: 4,
                      horizontal: 6,
                    ),
                    child: Row(
                      mainAxisSize: MainAxisSize.min,
                      children: [
                        Text(
                          'View Details',
                          style: context.textTheme.labelLarge?.copyWith(
                            color: context.colors.primary,
                            fontWeight: FontWeight.w600,
                          ),
                        ),
                        const SizedBox(width: 4),
                        Icon(
                          KasyIcons.northEast,
                          size: 16,
                          color: context.colors.primary,
                        ),
                      ],
                    ),
                  ),
                ],
              ),
            ),
          ),
        ],
      ),
    );
  }
}

class _FilterChipVariantContent extends StatefulWidget {
  const _FilterChipVariantContent();

  @override
  State<_FilterChipVariantContent> createState() =>
      _FilterChipVariantContentState();
}

class _FilterChipVariantContentState extends State<_FilterChipVariantContent> {
  bool _assistSelected = false;
  bool _tonalSelected = true;

  @override
  Widget build(BuildContext context) {
    return Wrap(
      spacing: KasySpacing.sm,
      runSpacing: KasySpacing.sm,
      children: [
        KasyChip(
          label: 'Assist filter',
          selected: _assistSelected,
          onSelected: (bool value) {
            setState(() {
              _assistSelected = value;
            });
          },
        ),
        KasyChip(
          label: 'Tonal filter',
          variant: KasyChipVariant.tonal,
          selected: _tonalSelected,
          onSelected: (bool value) {
            setState(() {
              _tonalSelected = value;
            });
          },
        ),
      ],
    );
  }
}

class _BadgeColorsPreview extends StatelessWidget {
  const _BadgeColorsPreview();

  @override
  Widget build(BuildContext context) {
    const List<KasyBadgeTone> tones = [
      KasyBadgeTone.neutral,
      KasyBadgeTone.primary,
      KasyBadgeTone.success,
      KasyBadgeTone.warning,
      KasyBadgeTone.danger,
    ];
    final List<Gradient> gradients = [
      KasyAvatarGradients.blue,
      KasyAvatarGradients.teal,
      KasyAvatarGradients.purple,
      KasyAvatarGradients.orange,
      KasyAvatarGradients.red,
    ];
    return Center(
      child: Row(
        mainAxisSize: MainAxisSize.min,
        children: List<Widget>.generate(tones.length, (int i) {
          return Padding(
            padding: EdgeInsets.only(right: i == tones.length - 1 ? 0 : 18),
            child: KasyBadged(
              badge: KasyBadge.dot(tone: tones[i]),
              child: KasyAvatar.gradientFill(
                size: KasyAvatarSize.medium,
                showShadow: false,
                gradient: gradients[i],
              ),
            ),
          );
        }),
      ),
    );
  }
}

class _BadgeSizesPreview extends StatelessWidget {
  const _BadgeSizesPreview();

  @override
  Widget build(BuildContext context) {
    return const Center(
      child: Row(
        mainAxisSize: MainAxisSize.min,
        children: [
          _BadgeSizeItem(label: 'sm', size: KasyBadgeSize.sm),
          SizedBox(width: 22),
          _BadgeSizeItem(label: 'md', size: KasyBadgeSize.md),
          SizedBox(width: 22),
          _BadgeSizeItem(label: 'lg', size: KasyBadgeSize.lg),
        ],
      ),
    );
  }
}

class _BadgeSizeItem extends StatelessWidget {
  final String label;
  final KasyBadgeSize size;

  const _BadgeSizeItem({required this.label, required this.size});

  @override
  Widget build(BuildContext context) {
    final KasyAvatarSize avatarSize = switch (size) {
      KasyBadgeSize.sm => KasyAvatarSize.small,
      KasyBadgeSize.md => KasyAvatarSize.medium,
      KasyBadgeSize.lg => KasyAvatarSize.large,
    };
    return Column(
      mainAxisSize: MainAxisSize.min,
      children: [
        KasyBadged(
          badge: KasyBadge(text: '5', size: size),
          child: KasyAvatar.gradientFill(
            size: avatarSize,
            showShadow: false,
            gradient: KasyAvatarGradients.red,
          ),
        ),
        const SizedBox(height: KasySpacing.sm),
        Text(label, style: context.textTheme.bodySmall),
      ],
    );
  }
}

class _BadgePlacementsPreview extends StatelessWidget {
  const _BadgePlacementsPreview();

  @override
  Widget build(BuildContext context) {
    const List<(KasyBadgePlacement, String)> placements = [
      (KasyBadgePlacement.topRight, 'top-right'),
      (KasyBadgePlacement.topLeft, 'top-left'),
      (KasyBadgePlacement.bottomRight, 'bottom-right'),
      (KasyBadgePlacement.bottomLeft, 'bottom-left'),
    ];
    return Center(
      child: Row(
        mainAxisSize: MainAxisSize.min,
        children: List<Widget>.generate(placements.length, (int i) {
          final (p, label) = placements[i];
          return Padding(
            padding: EdgeInsets.only(
              right: i == placements.length - 1 ? 0 : 22,
            ),
            child: Column(
              mainAxisSize: MainAxisSize.min,
              children: [
                KasyBadged(
                  placement: p,
                  badge: const KasyBadge.dot(),
                  child: KasyAvatar.gradientFill(
                    size: KasyAvatarSize.medium,
                    showShadow: false,
                    gradient: KasyAvatarGradients.purple,
                  ),
                ),
                const SizedBox(height: KasySpacing.sm),
                Text(label, style: context.textTheme.bodySmall),
              ],
            ),
          );
        }),
      ),
    );
  }
}

class _BadgeDotPreview extends StatelessWidget {
  const _BadgeDotPreview();

  static const List<(KasyBadgeTone, Gradient)> _items = [
    (KasyBadgeTone.neutral, KasyAvatarGradients.blue),
    (KasyBadgeTone.primary, KasyAvatarGradients.teal),
    (KasyBadgeTone.success, KasyAvatarGradients.purple),
    (KasyBadgeTone.warning, KasyAvatarGradients.red),
    (KasyBadgeTone.danger, KasyAvatarGradients.orange),
  ];

  @override
  Widget build(BuildContext context) {
    return Center(
      child: Row(
        mainAxisSize: MainAxisSize.min,
        children: List<Widget>.generate(_items.length, (int i) {
          final (tone, gradient) = _items[i];
          return Padding(
            padding: EdgeInsets.only(right: i == _items.length - 1 ? 0 : 18),
            child: KasyBadged(
              placement: KasyBadgePlacement.bottomRight,
              badge: KasyBadge.dot(tone: tone),
              child: KasyAvatar.gradientFill(
                size: KasyAvatarSize.medium,
                showShadow: false,
                gradient: gradient,
              ),
            ),
          );
        }),
      ),
    );
  }
}

class _BadgeVariantsPreview extends StatelessWidget {
  const _BadgeVariantsPreview();

  static const List<KasyBadgeTone> _tones = [
    KasyBadgeTone.neutral,
    KasyBadgeTone.primary,
    KasyBadgeTone.success,
    KasyBadgeTone.warning,
    KasyBadgeTone.danger,
  ];

  static const List<Gradient> _gradients = [
    KasyAvatarGradients.blue,
    KasyAvatarGradients.teal,
    KasyAvatarGradients.purple,
    KasyAvatarGradients.red,
    KasyAvatarGradients.orange,
  ];

  static const List<KasyAvatarTone> _avatarTones = [
    KasyAvatarTone.blue,
    KasyAvatarTone.neutral,
    KasyAvatarTone.green,
    KasyAvatarTone.orange,
    KasyAvatarTone.red,
  ];

  @override
  Widget build(BuildContext context) {
    return Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        _variantRow(context, 'Primary', _buildPrimaryRow(context)),
        const Divider(height: KasySpacing.xl),
        _variantRow(context, 'Secondary', _buildSecondaryRow(context)),
        const Divider(height: KasySpacing.xl),
        _variantRow(context, 'Soft', _buildSoftRow(context)),
      ],
    );
  }

  Widget _variantRow(BuildContext context, String label, Widget row) {
    return Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        Padding(
          padding: const EdgeInsets.only(bottom: KasySpacing.sm),
          child: Text(label, style: context.textTheme.bodySmall),
        ),
        Center(child: row),
      ],
    );
  }

  Widget _buildPrimaryRow(BuildContext context) {
    return Row(
      mainAxisSize: MainAxisSize.min,
      children: List.generate(_tones.length, (int i) {
        return Padding(
          padding: EdgeInsets.only(right: i == _tones.length - 1 ? 0 : 14),
          child: KasyBadged(
            badge: KasyBadge(text: '5', tone: _tones[i]),
            child: KasyAvatar.gradientFill(
              size: KasyAvatarSize.medium,
              showShadow: false,
              gradient: _gradients[i],
            ),
          ),
        );
      }),
    );
  }

  Widget _buildSecondaryRow(BuildContext context) {
    return Row(
      mainAxisSize: MainAxisSize.min,
      children: List.generate(_tones.length, (int i) {
        return Padding(
          padding: EdgeInsets.only(right: i == _tones.length - 1 ? 0 : 14),
          child: KasyBadged(
            badge: KasyBadge(text: '5', tone: _tones[i]),
            child: KasyAvatar(
              initials: 'JD',
              tone: _avatarTones[i],
            ),
          ),
        );
      }),
    );
  }

  Widget _buildSoftRow(BuildContext context) {
    return Row(
      mainAxisSize: MainAxisSize.min,
      children: List.generate(_tones.length, (int i) {
        return Padding(
          padding: EdgeInsets.only(right: i == _tones.length - 1 ? 0 : 14),
          child: KasyBadged(
            badge: KasyBadge(text: '5', tone: _tones[i]),
            child: KasyAvatar(
              initials: 'JD',
              tone: _avatarTones[i],
              fallbackSurface: KasyAvatarFallbackSurface.soft,
            ),
          ),
        );
      }),
    );
  }
}

class _BadgeWithContentPreview extends StatelessWidget {
  const _BadgeWithContentPreview();

  @override
  Widget build(BuildContext context) {
    return const Center(
      child: Row(
        mainAxisSize: MainAxisSize.min,
        children: [
          _BadgeContentItem(
            label: 'Number',
            badge: KasyBadge(text: '5'),
            gradient: KasyAvatarGradients.orange,
          ),
          SizedBox(width: KasySpacing.lg),
          _BadgeContentItem(
            label: 'Text',
            badge: KasyBadge(text: 'New', tone: KasyBadgeTone.primary),
            gradient: KasyAvatarGradients.blue,
          ),
          SizedBox(width: KasySpacing.lg),
          _BadgeContentItem(
            label: 'Overflow',
            badge: KasyBadge(text: '99+'),
            gradient: KasyAvatarGradients.purple,
          ),
        ],
      ),
    );
  }
}

class _BadgeContentItem extends StatelessWidget {
  final String label;
  final KasyBadge badge;
  final Gradient gradient;

  const _BadgeContentItem({
    required this.label,
    required this.badge,
    required this.gradient,
  });

  @override
  Widget build(BuildContext context) {
    return Column(
      mainAxisSize: MainAxisSize.min,
      children: [
        KasyBadged(
          badge: badge,
          child: KasyAvatar.gradientFill(
            size: KasyAvatarSize.medium,
            showShadow: false,
            gradient: gradient,
          ),
        ),
        const SizedBox(height: KasySpacing.sm),
        Text(label, style: context.textTheme.bodySmall),
      ],
    );
  }
}

class _BasicTextFieldVariantContent extends StatelessWidget {
  const _BasicTextFieldVariantContent();

  @override
  Widget build(BuildContext context) {
    return const KasyTextField(
      hint: 'Enter your email',
      keyboardType: TextInputType.emailAddress,
      textInputAction: TextInputAction.done,
    );
  }
}

class _TextFieldWithLabelDescriptionVariantContent extends StatelessWidget {
  const _TextFieldWithLabelDescriptionVariantContent();

  @override
  Widget build(BuildContext context) {
    return const KasyTextField(
      label: 'Email',
      hint: 'Enter your email',
      description: "We'll never share your email with anyone else.",
      keyboardType: TextInputType.emailAddress,
      textInputAction: TextInputAction.done,
    );
  }
}

class _TextFieldStandardContent extends StatelessWidget {
  const _TextFieldStandardContent();

  @override
  Widget build(BuildContext context) {
    return const KasyTextField(
      label: 'Email',
      hint: 'Enter your email',
      contentType: KasyTextFieldContentType.email,
      textInputAction: TextInputAction.done,
    );
  }
}

class _TextFieldWithIconContent extends StatefulWidget {
  const _TextFieldWithIconContent();

  @override
  State<_TextFieldWithIconContent> createState() =>
      _TextFieldWithIconContentState();
}

class _TextFieldWithIconContentState extends State<_TextFieldWithIconContent> {
  late final TextEditingController _messageController;

  @override
  void initState() {
    super.initState();
    _messageController = TextEditingController();
    _messageController.addListener(() => setState(() {}));
  }

  @override
  void dispose() {
    _messageController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    final TextStyle labelStyle =
        context.textTheme.labelSmall?.copyWith(
          color: context.colors.muted,
          letterSpacing: 1.2,
          fontWeight: FontWeight.w700,
        ) ??
        const TextStyle();
    return Column(
      mainAxisSize: MainAxisSize.min,
      crossAxisAlignment: CrossAxisAlignment.stretch,
      children: [
        Text('PHONE', style: labelStyle),
        const SizedBox(height: KasySpacing.sm),
        const KasyTextField(
          label: 'Phone',
          hint: '5550000000',
          prefix: Icon(KasyIcons.phone),
          contentType: KasyTextFieldContentType.phone,
        ),
        const SizedBox(height: KasySpacing.lg),
        Text('PASSWORD', style: labelStyle),
        const SizedBox(height: KasySpacing.sm),
        const KasyTextField(
          label: 'Password',
          hint: 'Enter your password',
          contentType: KasyTextFieldContentType.password,
        ),
        const SizedBox(height: KasySpacing.lg),
        Text('MESSAGE', style: labelStyle),
        const SizedBox(height: KasySpacing.sm),
        KasyTextField(
          controller: _messageController,
          label: 'Message',
          hint: 'Type here...',
          prefix: const Icon(KasyIcons.message),
          suffix: _messageController.text.isEmpty
              ? null
              : GestureDetector(
                  onTap: () => _messageController.clear(),
                  child: const Icon(KasyIcons.close),
                ),
        ),
      ],
    );
  }
}

class _TextFieldMultilineContent extends StatefulWidget {
  const _TextFieldMultilineContent();

  @override
  State<_TextFieldMultilineContent> createState() =>
      _TextFieldMultilineContentState();
}

class _TextFieldMultilineContentState
    extends State<_TextFieldMultilineContent> {
  late final TextEditingController _controller;

  @override
  void initState() {
    super.initState();
    _controller = TextEditingController(
      text: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.',
    );
  }

  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return KasyTextField(
      controller: _controller,
      label: 'Description',
      hint: 'Type here...',
      maxLines: 5,
      textInputAction: TextInputAction.newline,
    );
  }
}

// ---------------------------------------------------------------------------
// TextArea preview widgets
// ---------------------------------------------------------------------------

class _TextAreaBasicContent extends StatelessWidget {
  const _TextAreaBasicContent();

  @override
  Widget build(BuildContext context) {
    return const KasyTextArea(hint: 'Enter your message');
  }
}

class _TextAreaWithLabelDescriptionContent extends StatelessWidget {
  const _TextAreaWithLabelDescriptionContent();

  @override
  Widget build(BuildContext context) {
    return const KasyTextArea(
      label: 'Message',
      hint: 'Enter your message here...',
      description: 'Please provide as much detail as possible.',
    );
  }
}

void _noop() {}

void _triggerTapFeedback() {}

/// Os hosts de preview aplicam largura máxima ao conteúdo; uma [Row] centralizada
/// mantém [KasyButton] sem `expand` com largura intrínseca ao rótulo.
Widget _previewIntrinsicLaunch(Widget child) {
  return Row(
    mainAxisAlignment: MainAxisAlignment.center,
    children: <Widget>[child],
  );
}

const List<KasyAccordionItemData> _kAccordionItems = <KasyAccordionItemData>[
  KasyAccordionItemData(
    icon: KasyIcons.send,
    title: 'How do I place an order?',
    description:
        'Open your cart, review your items, choose a payment method, and confirm. You will immediately receive an order confirmation.',
  ),
  KasyAccordionItemData(
    icon: KasyIcons.refresh,
    title: 'Can I modify or cancel my order?',
    description:
        'Lorem ipsum dolor sit amet consectetur. Netus nunc mauris risus consequat. Libero placerat dignissim consectetur nisl. Ornare imperdiet amet lorem adipiscing.',
  ),
  KasyAccordionItemData(
    icon: KasyIcons.payment,
    title: 'How much does shipping cost?',
    description:
        'Shipping cost depends on your location and delivery method. You can always see the final amount before confirming payment.',
  ),
  KasyAccordionItemData(
    icon: KasyIcons.language,
    title: 'Do you ship internationally?',
    description:
        'Yes. International delivery is available for selected countries and may include import taxes calculated at checkout.',
  ),
];

const List<KasyAccordionItemData> _kAccordionElevatedItems =
    <KasyAccordionItemData>[
      KasyAccordionItemData(
        icon: KasyIcons.shoppingBag,
        title: 'How do I place an order?',
        description:
            'Open your cart, review your items, choose a payment method, '
            'and confirm. You will immediately receive an order confirmation.',
      ),
      KasyAccordionItemData(
        icon: KasyIcons.ticket,
        title: 'Can I modify or cancel my order?',
        description:
            'Lorem ipsum dolor sit amet consectetur. Netus nunc mauris risus '
            'consequat. Libero placerat dignissim consectetur nisl. Ornare '
            'imperdiet amet lorem adipiscing.',
      ),
      KasyAccordionItemData(
        icon: KasyIcons.packageOutline,
        title: 'How much does shipping cost?',
        description:
            'Shipping cost depends on your location and delivery method. You '
            'can always see the final amount before confirming payment.',
      ),
    ];

// ── BottomSheet previews ─────────────────────────────────────────────────────

Widget _buildBottomSheetBasic(BuildContext context) {
  return _BottomSheetTrigger(
    label: 'Basic bottom sheet',
    builder: (sheetCtx) => KasyBottomSheet(
      icon: KasyIcons.security,
      iconTone: KasySheetIconTone.success,
      title: 'Keep yourself safe',
      message:
          'Update your software to the latest version for better security and performance.',
      actions: [
        KasyButton(
          label: 'Update Now',
          expand: true,
          onPressed: () => Navigator.of(sheetCtx).pop(),
        ),
        KasyButton(
          label: 'Later',
          variant: KasyButtonVariant.tertiary,
          expand: true,
          onPressed: () => Navigator.of(sheetCtx).pop(),
        ),
      ],
    ),
  );
}

Widget _buildBottomSheetTones(BuildContext context) {
  return Column(
    mainAxisSize: MainAxisSize.min,
    crossAxisAlignment: CrossAxisAlignment.stretch,
    children: [
      _BottomSheetTrigger(
        label: 'Info',
        builder: (sheetCtx) => KasyBottomSheet(
          icon: KasyIcons.info,
          title: 'New feature available',
          message: "Explore what's new in this version of the app.",
          actions: [
            KasyButton(
              label: 'Got it',
              expand: true,
              onPressed: () => Navigator.of(sheetCtx).pop(),
            ),
          ],
        ),
      ),
      const SizedBox(height: KasySpacing.sm),
      _BottomSheetTrigger(
        label: 'Success',
        builder: (sheetCtx) => KasyBottomSheet(
          icon: KasyIcons.checkCircle,
          iconTone: KasySheetIconTone.success,
          title: 'Payment complete',
          message: 'Your order has been confirmed and is on its way.',
          actions: [
            KasyButton(
              label: 'Done',
              expand: true,
              backgroundColor: sheetCtx.colors.success,
              foregroundColor: sheetCtx.colors.onSuccess,
              onPressed: () => Navigator.of(sheetCtx).pop(),
            ),
          ],
        ),
      ),
      const SizedBox(height: KasySpacing.sm),
      _BottomSheetTrigger(
        label: 'Warning',
        builder: (sheetCtx) => KasyBottomSheet(
          icon: KasyIcons.time,
          iconTone: KasySheetIconTone.warning,
          title: 'Session expiring',
          message: "You'll be signed out in 5 minutes due to inactivity.",
          actions: [
            KasyButton(
              label: 'Stay signed in',
              expand: true,
              onPressed: () => Navigator.of(sheetCtx).pop(),
            ),
            KasyButton(
              label: 'Sign out',
              variant: KasyButtonVariant.tertiary,
              expand: true,
              onPressed: () => Navigator.of(sheetCtx).pop(),
            ),
          ],
        ),
      ),
      const SizedBox(height: KasySpacing.sm),
      _BottomSheetTrigger(
        label: 'Danger',
        builder: (sheetCtx) => KasyBottomSheet(
          icon: KasyIcons.trash,
          iconTone: KasySheetIconTone.danger,
          title: 'Delete account',
          message:
              'This action is permanent. All your data will be removed and cannot be recovered.',
          actions: [
            KasyButton(
              label: 'Delete forever',
              variant: KasyButtonVariant.destructive,
              expand: true,
              onPressed: () => Navigator.of(sheetCtx).pop(),
            ),
            KasyButton(
              label: 'Cancel',
              variant: KasyButtonVariant.tertiary,
              expand: true,
              onPressed: () => Navigator.of(sheetCtx).pop(),
            ),
          ],
        ),
      ),
    ],
  );
}

Widget _buildBottomSheetDetached(BuildContext context) {
  return _BottomSheetTrigger(
    label: 'Detached bottom sheet',
    builder: (sheetCtx) => Padding(
      padding: EdgeInsets.fromLTRB(
        KasySpacing.md,
        0,
        KasySpacing.md,
        MediaQuery.paddingOf(sheetCtx).bottom + KasySpacing.md,
      ),
      child: ClipRRect(
        borderRadius: BorderRadius.circular(KasyRadius.xl),
        child: KasyBottomSheet(
          addBottomSafeArea: false,
          icon: KasyIcons.payment,
          iconTone: KasySheetIconTone.success,
          title: 'Oh! Your wallet is empty',
          message: "You'll need to top up to buy",
          actions: [
            KasyButton(
              label: 'Add Cash',
              expand: true,
              backgroundColor: sheetCtx.colors.success,
              foregroundColor: sheetCtx.colors.onSuccess,
              onPressed: () => Navigator.of(sheetCtx).pop(),
            ),
            Builder(
              builder: (ctx) => Center(
                child: Text(
                  'Apple Pay • Mastercard • Visa • Amex',
                  style: ctx.textTheme.bodySmall?.copyWith(
                    color: ctx.colors.muted,
                  ),
                ),
              ),
            ),
          ],
        ),
      ),
    ),
  );
}

Widget _buildBottomSheetBlurOverlay(BuildContext context) {
  return _BottomSheetBlurTrigger(
    label: 'Bottom sheet with blur overlay',
    builder: (sheetCtx) => KasyBottomSheet(
      title: 'Delete account?',
      message:
          "If you delete your account, you won't be able to restore it or receive support.\n\n"
          'Our app will no longer be able to provide support for any of your trips, '
          'such as providing a refund or locking for lost items.\n\n'
          'For other deletion options, see our Privacy Policy.',
      actions: [
        KasyButton(
          label: 'Delete forever',
          variant: KasyButtonVariant.destructive,
          expand: true,
          onPressed: () => Navigator.of(sheetCtx).pop(),
        ),
        KasyButton(
          label: 'Cancel',
          variant: KasyButtonVariant.tertiary,
          expand: true,
          onPressed: () => Navigator.of(sheetCtx).pop(),
        ),
      ],
    ),
  );
}

Widget _buildBottomSheetScrollableSnap(BuildContext context) {
  return _BottomSheetTrigger(
    label: 'Scrollable with snap points',
    isScrollControlled: true,
    builder: (sheetCtx) =>
        _SnapSheetContainer(onClose: () => Navigator.of(sheetCtx).pop()),
  );
}

class _SnapSheetContainer extends StatefulWidget {
  final VoidCallback onClose;

  const _SnapSheetContainer({required this.onClose});

  @override
  State<_SnapSheetContainer> createState() => _SnapSheetContainerState();
}

class _SnapSheetContainerState extends State<_SnapSheetContainer> {
  final DraggableScrollableController _controller =
      DraggableScrollableController();

  @override
  void initState() {
    super.initState();
    WidgetsBinding.instance.addPostFrameCallback((_) {
      if (mounted) {
        _controller.animateTo(
          0.42,
          duration: const Duration(milliseconds: 360),
          curve: Curves.easeOutCubic,
        );
      }
    });
  }

  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return DraggableScrollableSheet(
      controller: _controller,
      initialChildSize: 0.13,
      minChildSize: 0.13,
      maxChildSize: 0.82,
      snap: true,
      snapSizes: const [0.13, 0.42, 0.68, 0.82],
      expand: false,
      builder: (_, scrollController) => _SnapSheet(
        scrollController: scrollController,
        onClose: widget.onClose,
      ),
    );
  }
}

class _SnapSheet extends StatelessWidget {
  final ScrollController scrollController;
  final VoidCallback onClose;

  const _SnapSheet({required this.scrollController, required this.onClose});

  @override
  Widget build(BuildContext context) {
    final double bottomPad = MediaQuery.paddingOf(context).bottom;
    return DecoratedBox(
      decoration: BoxDecoration(
        color: context.colors.surface,
        borderRadius: const BorderRadius.vertical(
          top: Radius.circular(KasyRadius.xl),
        ),
      ),
      child: Column(
        children: [
          Expanded(
            child: CustomScrollView(
              controller: scrollController,
              slivers: [
                SliverToBoxAdapter(
                  child: Padding(
                    padding: const EdgeInsets.only(top: KasySpacing.smd),
                    child: Center(
                      child: Container(
                        width: 36,
                        height: 4,
                        decoration: BoxDecoration(
                          color: context.colors.outline.withValues(alpha: 0.35),
                          borderRadius: BorderRadius.circular(KasyRadius.full),
                        ),
                      ),
                    ),
                  ),
                ),
                SliverToBoxAdapter(
                  child: Padding(
                    padding: const EdgeInsets.fromLTRB(
                      KasySpacing.lg,
                      KasySpacing.md,
                      KasySpacing.md,
                      KasySpacing.sm,
                    ),
                    child: Row(
                      children: [
                        Expanded(
                          child: Text(
                            'Select a way to travel',
                            style: context.textTheme.titleLarge?.copyWith(
                              fontWeight: FontWeight.w700,
                              fontSize: 20,
                              color: context.colors.onSurface,
                            ),
                          ),
                        ),
                        IconButton(
                          icon: Icon(
                            KasyIcons.close,
                            size: 18,
                            color: context.colors.onSurface,
                          ),
                          style: IconButton.styleFrom(
                            backgroundColor: context.colors.surfaceNeutralSoft,
                          ),
                          onPressed: onClose,
                        ),
                      ],
                    ),
                  ),
                ),
                SliverPadding(
                  padding: const EdgeInsets.symmetric(
                    horizontal: KasySpacing.lg,
                  ),
                  sliver: SliverList.list(
                    children: [
                      const _SnapTaxiRow(
                        icon: Icons.bolt,
                        label: 'Taxi Priority',
                        subtitle: 'in 1 min • 4',
                        price: 'c. €12-19',
                      ),
                      const _SnapTaxiRow(
                        icon: Icons.star_border_rounded,
                        label: 'Taxi Comfort',
                        subtitle: 'in 6 min • 4',
                        price: 'c. €11-18',
                      ),
                      _SnapTaxiRow(
                        icon: Icons.eco,
                        iconBackground: context.colors.success,
                        label: 'Green Taxi',
                        subtitle: 'in 6 min • 4',
                        price: 'c. €11-17',
                      ),
                      const _SnapTaxiRow(
                        icon: Icons.directions_car,
                        label: 'Premium',
                        subtitle: 'in 10 min • 4',
                        price: '€30.89',
                        badge: 'High end cars, top drivers',
                        highlighted: true,
                      ),
                      const _SnapTaxiRow(
                        icon: Icons.directions_car,
                        label: 'Taxi XL',
                        subtitle: 'in 2 min • 5-8',
                        price: 'c. €12-19',
                      ),
                      const SizedBox(height: KasySpacing.md),
                      _SnapPromoRow(),
                      const SizedBox(height: KasySpacing.sm),
                      _SnapPaymentRow(),
                      const SizedBox(height: KasySpacing.lg),
                      const _SnapSection(
                        title: 'Trip Details',
                        body:
                            'Estimated arrival time: 10 minutes\nDistance: 4.2 km\n\n'
                            'Your driver will arrive at the pickup location shortly. '
                            'Please be ready when they arrive.',
                      ),
                      const SizedBox(height: KasySpacing.lg),
                      const _SnapSection(
                        title: 'Important Information',
                        body:
                            '• All prices include taxes and fees\n'
                            '• Payment will be processed after trip completion\n'
                            '• Cancellation fees may apply if cancelled after 2 minutes\n'
                            '• For support, contact us through the app or call +1-800-TAXI-HELP',
                      ),
                      const SizedBox(height: KasySpacing.lg),
                      const _SnapSection(
                        title: 'Safety & Security',
                        body:
                            'All our drivers are verified and background-checked. '
                            'Your safety is our top priority.\n\n'
                            'Share your trip details with friends and family for added security.',
                      ),
                      const SizedBox(height: KasySpacing.lg),
                    ],
                  ),
                ),
              ],
            ),
          ),
          DecoratedBox(
            decoration: BoxDecoration(
              border: Border(
                top: BorderSide(
                  color: context.colors.outline.withValues(alpha: 0.30),
                ),
              ),
            ),
            child: Padding(
              padding: EdgeInsets.fromLTRB(
                KasySpacing.md,
                KasySpacing.md,
                KasySpacing.md,
                bottomPad + KasySpacing.lg,
              ),
              child: KasyButton(
                label: 'Order Premium now',
                variant: KasyButtonVariant.destructive,
                expand: true,
                onPressed: onClose,
              ),
            ),
          ),
        ],
      ),
    );
  }
}

class _SnapTaxiRow extends StatelessWidget {
  final IconData icon;
  final Color? iconBackground;
  final String label;
  final String subtitle;
  final String price;
  final String? badge;
  final bool highlighted;

  const _SnapTaxiRow({
    required this.icon,
    this.iconBackground,
    required this.label,
    required this.subtitle,
    required this.price,
    this.badge,
    this.highlighted = false,
  });

  @override
  Widget build(BuildContext context) {
    final Color bg = iconBackground ?? context.colors.onSurface;
    final Widget row = Padding(
      padding: const EdgeInsets.fromLTRB(6, KasySpacing.sm, 0, KasySpacing.sm),
      child: Row(
        children: [
          Container(
            width: 44,
            height: 44,
            decoration: BoxDecoration(color: bg, shape: BoxShape.circle),
            child: Icon(icon, size: 20, color: Colors.white),
          ),
          const SizedBox(width: KasySpacing.smd),
          Expanded(
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                Text(
                  label,
                  style: context.textTheme.bodyMedium?.copyWith(
                    fontWeight: FontWeight.w600,
                    color: context.colors.onSurface,
                  ),
                ),
                if (badge != null)
                  Text(
                    badge!,
                    style: context.textTheme.bodySmall?.copyWith(
                      color: context.colors.success,
                    ),
                  )
                else
                  Text(
                    subtitle,
                    style: context.textTheme.bodySmall?.copyWith(
                      color: context.colors.muted,
                    ),
                  ),
              ],
            ),
          ),
          SizedBox(
            width: 72,
            child: Text(
              price,
              textAlign: TextAlign.right,
              style: context.textTheme.bodyMedium?.copyWith(
                fontWeight: FontWeight.w500,
                color: context.colors.onSurface,
              ),
            ),
          ),
          Padding(
            padding: const EdgeInsets.only(left: KasySpacing.xs),
            child: Icon(
              Icons.chevron_right,
              size: 18,
              color: highlighted ? context.colors.muted : Colors.transparent,
            ),
          ),
        ],
      ),
    );
    if (!highlighted) return row;
    return DecoratedBox(
      decoration: BoxDecoration(
        color: context.colors.success.withValues(alpha: 0.08),
        borderRadius: BorderRadius.circular(KasyRadius.md),
      ),
      child: row,
    );
  }
}

class _SnapPromoRow extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return DecoratedBox(
      decoration: BoxDecoration(
        color: context.colors.warning.withValues(alpha: 0.08),
        borderRadius: BorderRadius.circular(KasyRadius.md),
      ),
      child: Padding(
        padding: const EdgeInsets.symmetric(
          horizontal: KasySpacing.smd,
          vertical: KasySpacing.sm,
        ),
        child: Row(
          children: [
            Container(
              width: 36,
              height: 36,
              decoration: BoxDecoration(
                color: context.colors.warning,
                shape: BoxShape.circle,
              ),
              child: const Center(
                child: Text(
                  'P',
                  style: TextStyle(
                    color: Colors.white,
                    fontWeight: FontWeight.w700,
                    fontSize: 15,
                  ),
                ),
              ),
            ),
            const SizedBox(width: KasySpacing.smd),
            Expanded(
              child: Column(
                crossAxisAlignment: CrossAxisAlignment.start,
                children: [
                  Text(
                    '10% off all trips with PLUS',
                    style: context.textTheme.bodySmall?.copyWith(
                      fontWeight: FontWeight.w600,
                      color: context.colors.onSurface,
                    ),
                  ),
                  Text(
                    'Subscribe for €6.99/month',
                    style: context.textTheme.bodySmall?.copyWith(
                      color: context.colors.muted,
                    ),
                  ),
                ],
              ),
            ),
            Icon(Icons.chevron_right, size: 18, color: context.colors.muted),
          ],
        ),
      ),
    );
  }
}

class _SnapPaymentRow extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return DecoratedBox(
      decoration: BoxDecoration(
        color: context.colors.surfaceNeutralSoft,
        borderRadius: BorderRadius.circular(KasyRadius.md),
      ),
      child: Padding(
        padding: const EdgeInsets.symmetric(
          horizontal: KasySpacing.smd,
          vertical: KasySpacing.sm,
        ),
        child: Row(
          children: [
            Container(
              width: 36,
              height: 36,
              decoration: BoxDecoration(
                color: KasyColors.semanticError,
                borderRadius: BorderRadius.circular(KasyRadius.sm),
              ),
              child: const Icon(Icons.person, size: 20, color: Colors.white),
            ),
            const SizedBox(width: KasySpacing.smd),
            Expanded(
              child: Column(
                crossAxisAlignment: CrossAxisAlignment.start,
                children: [
                  Text(
                    'Personal',
                    style: context.textTheme.bodySmall?.copyWith(
                      fontWeight: FontWeight.w600,
                      color: context.colors.onSurface,
                    ),
                  ),
                  Text(
                    'Visa ••••',
                    style: context.textTheme.bodySmall?.copyWith(
                      color: context.colors.muted,
                    ),
                  ),
                ],
              ),
            ),
            Icon(Icons.chevron_right, size: 18, color: context.colors.muted),
          ],
        ),
      ),
    );
  }
}

class _SnapSection extends StatelessWidget {
  final String title;
  final String body;

  const _SnapSection({required this.title, required this.body});

  @override
  Widget build(BuildContext context) {
    return Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        Text(
          title,
          style: context.textTheme.titleSmall?.copyWith(
            fontWeight: FontWeight.w700,
            color: context.colors.onSurface,
          ),
        ),
        const SizedBox(height: KasySpacing.xs),
        Text(
          body,
          style: context.textTheme.bodyMedium?.copyWith(
            color: context.colors.onSurface.withValues(alpha: 0.65),
            height: 1.5,
          ),
        ),
      ],
    );
  }
}

Widget _buildBottomSheetTextInput(BuildContext context) {
  return _BottomSheetTrigger(
    label: 'Bottom sheet with text field',
    isScrollControlled: true,
    builder: (sheetCtx) =>
        _TextInputSheet(onClose: () => Navigator.of(sheetCtx).pop()),
  );
}

class _TextInputSheet extends StatefulWidget {
  final VoidCallback onClose;

  const _TextInputSheet({required this.onClose});

  @override
  State<_TextInputSheet> createState() => _TextInputSheetState();
}

class _TextInputSheetState extends State<_TextInputSheet> {
  final TextEditingController _textController = TextEditingController();
  final DraggableScrollableController _dragController =
      DraggableScrollableController();
  String _query = '';
  bool _wasKeyboardOpen = false;

  static const double _initialSize = 0.58;
  static const double _maxSize = 0.92;

  static const List<({String initials, String name, String email})>
  _contacts = [
    (initials: 'JD', name: 'John Doe', email: 'john.doe@example.com'),
    (initials: 'JS', name: 'Jane Smith', email: 'jane.smith@example.com'),
    (initials: 'AJ', name: 'Alice Johnson', email: 'alice.johnson@example.com'),
    (initials: 'BW', name: 'Bob Williams', email: 'bob.williams@example.com'),
    (initials: 'CB', name: 'Charlie Brown', email: 'charlie.brown@example.com'),
    (initials: 'DP', name: 'Diana Prince', email: 'diana.prince@example.com'),
    (initials: 'EN', name: 'Edward Norton', email: 'edward.norton@example.com'),
    (initials: 'FA', name: 'Fiona Apple', email: 'fiona.apple@example.com'),
    (initials: 'GL', name: 'George Lucas', email: 'george.lucas@example.com'),
    (
      initials: 'HM',
      name: 'Hannah Montana',
      email: 'hannah.montana@example.com',
    ),
    (initials: 'IK', name: 'Ivan Koch', email: 'ivan.koch@example.com'),
    (initials: 'JL', name: 'Julia Lima', email: 'julia.lima@example.com'),
    (initials: 'KR', name: 'Kevin Ross', email: 'kevin.ross@example.com'),
    (initials: 'LM', name: 'Laura Mendes', email: 'laura.mendes@example.com'),
    (initials: 'MN', name: 'Marcus Nolan', email: 'marcus.nolan@example.com'),
    (initials: 'NP', name: 'Nina Park', email: 'nina.park@example.com'),
    (initials: 'OQ', name: 'Oscar Quinn', email: 'oscar.quinn@example.com'),
  ];

  static const List<KasyAvatarTone> _tones = [
    KasyAvatarTone.blue,
    KasyAvatarTone.neutral,
    KasyAvatarTone.green,
    KasyAvatarTone.orange,
    KasyAvatarTone.red,
  ];

  @override
  void initState() {
    super.initState();
    _textController.addListener(() {
      setState(() => _query = _textController.text.toLowerCase());
    });
  }

  @override
  void dispose() {
    _textController.dispose();
    _dragController.dispose();
    super.dispose();
  }

  void _expandForKeyboard() {
    WidgetsBinding.instance.addPostFrameCallback((_) {
      if (_dragController.isAttached &&
          _dragController.size < _maxSize - 0.01) {
        _dragController.animateTo(
          _maxSize,
          duration: const Duration(milliseconds: 320),
          curve: Curves.easeOutCubic,
        );
      }
    });
  }

  @override
  Widget build(BuildContext context) {
    final bool hasKeyboard = MediaQuery.viewInsetsOf(context).bottom > 80;
    if (hasKeyboard && !_wasKeyboardOpen) {
      _wasKeyboardOpen = true;
      _expandForKeyboard();
    } else if (!hasKeyboard) {
      _wasKeyboardOpen = false;
    }

    final List<({String initials, String name, String email})> filtered =
        _contacts
            .where(
              (c) =>
                  c.name.toLowerCase().contains(_query) ||
                  c.email.toLowerCase().contains(_query),
            )
            .toList();

    return DraggableScrollableSheet(
      controller: _dragController,
      initialChildSize: _initialSize,
      minChildSize: 0.35,
      maxChildSize: _maxSize,
      expand: false,
      snap: true,
      snapSizes: const [_initialSize, _maxSize],
      builder: (_, ScrollController scrollController) {
        return Container(
          decoration: BoxDecoration(
            color: context.colors.surface,
            borderRadius: const BorderRadius.vertical(
              top: Radius.circular(KasyRadius.xl),
            ),
          ),
          child: CustomScrollView(
            controller: scrollController,
            slivers: [
              SliverToBoxAdapter(
                child: Padding(
                  padding: const EdgeInsets.only(top: KasySpacing.smd),
                  child: Center(
                    child: Container(
                      width: 36,
                      height: 4,
                      decoration: BoxDecoration(
                        color: context.colors.outline.withValues(alpha: 0.35),
                        borderRadius: BorderRadius.circular(KasyRadius.full),
                      ),
                    ),
                  ),
                ),
              ),
              SliverToBoxAdapter(
                child: Padding(
                  padding: const EdgeInsets.fromLTRB(
                    KasySpacing.md,
                    KasySpacing.md,
                    KasySpacing.md,
                    KasySpacing.sm,
                  ),
                  child: KasyTextField(
                    controller: _textController,
                    variant: KasyTextFieldVariant.secondary,
                    hint: 'Search by name or email...',
                    prefix: Icon(
                      Icons.search,
                      size: 20,
                      color: context.colors.muted,
                    ),
                    suffix: _query.isNotEmpty
                        ? GestureDetector(
                            onTap: () => _textController.clear(),
                            child: Icon(
                              KasyIcons.close,
                              size: 18,
                              color: context.colors.muted,
                            ),
                          )
                        : null,
                  ),
                ),
              ),
              if (filtered.isEmpty)
                SliverFillRemaining(
                  child: Center(
                    child: Column(
                      mainAxisSize: MainAxisSize.min,
                      children: [
                        Icon(
                          Icons.search,
                          size: 40,
                          color: context.colors.muted,
                        ),
                        const SizedBox(height: KasySpacing.sm),
                        Text(
                          'No users found',
                          style: context.textTheme.titleSmall?.copyWith(
                            color: context.colors.onSurface,
                            fontWeight: FontWeight.w600,
                          ),
                        ),
                        const SizedBox(height: KasySpacing.xs),
                        Text(
                          'Try a different search term',
                          style: context.textTheme.bodySmall?.copyWith(
                            color: context.colors.muted,
                          ),
                        ),
                      ],
                    ),
                  ),
                )
              else
                SliverPadding(
                  padding: const EdgeInsets.fromLTRB(
                    KasySpacing.md,
                    0,
                    KasySpacing.md,
                    KasySpacing.xl,
                  ),
                  sliver: SliverList.builder(
                    itemCount: filtered.length,
                    itemBuilder: (_, int i) {
                          final contact = filtered[i];
                          final int originalIndex = _contacts.indexOf(contact);
                          return Padding(
                            padding: const EdgeInsets.symmetric(
                              vertical: KasySpacing.sm,
                            ),
                            child: Row(
                              children: [
                                KasyAvatar(
                                  initials: contact.initials,
                                  tone: _tones[originalIndex % _tones.length],
                                  size: KasyAvatarSize.small,
                                ),
                                const SizedBox(width: KasySpacing.smd),
                                Expanded(
                                  child: Column(
                                    crossAxisAlignment:
                                        CrossAxisAlignment.start,
                                    children: [
                                      Text(
                                        contact.name,
                                        style: context.textTheme.bodyMedium
                                            ?.copyWith(
                                              fontWeight: FontWeight.w600,
                                              color: context.colors.onSurface,
                                            ),
                                      ),
                                      Text(
                                        contact.email,
                                        style: context.textTheme.bodySmall
                                            ?.copyWith(
                                              color: context.colors.muted,
                                            ),
                                      ),
                                    ],
                                  ),
                                ),
                              ],
                            ),
                          );
                        },
                      ),
                ),
            ],
          ),
        );
      },
    );
  }
}

Widget _buildBottomSheetNativeModal(BuildContext context) {
  return Padding(
    padding: const EdgeInsets.symmetric(
      horizontal: KasySpacing.pageHorizontalGutter,
    ),
    child: _previewIntrinsicLaunch(
      KasyButton(
        label: 'Page sheet',
        variant: KasyButtonVariant.soft,
        onPressed: () {
          _triggerTapFeedback();
          showKasyBottomSheet<void>(
            context: context,
            isScrollControlled: true,
            builder: (sheetCtx) => FractionallySizedBox(
              heightFactor: 0.92,
              child: ClipRRect(
                borderRadius: const BorderRadius.vertical(
                  top: Radius.circular(KasyRadius.xl),
                ),
                child: ColoredBox(
                  color: sheetCtx.colors.background,
                  child: Column(
                    crossAxisAlignment: CrossAxisAlignment.stretch,
                    children: [
                      const KasyAppBar(
                        title: 'Page sheet',
                        style: KasyAppBarStyle.rootTab,
                        useSafeArea: false,
                        toolbarHeight: 48,
                        topInset: 10,
                      ),
                      Expanded(
                        child: Padding(
                          padding: const EdgeInsets.symmetric(
                            horizontal: KasySpacing.lg,
                            vertical: KasySpacing.lg,
                          ),
                          child: Column(
                            crossAxisAlignment: CrossAxisAlignment.start,
                            children: [
                              Text(
                                'A page sheet behaves like a screen. Tap a button below to see nested interactions.',
                                style: sheetCtx.textTheme.bodyMedium?.copyWith(
                                  color: sheetCtx.colors.onSurface
                                      .withValues(alpha: 0.6),
                                  height: 1.5,
                                ),
                              ),
                              const SizedBox(height: KasySpacing.lg),
                              _BottomSheetTrigger(
                                label: 'Open bottom sheet',
                                builder: (innerCtx) => KasyBottomSheet(
                                  icon: KasyIcons.security,
                                  iconTone: KasySheetIconTone.success,
                                  title: 'Keep yourself safe',
                                  message:
                                      'Update your software to the latest version for better security and performance.',
                                  actions: [
                                    KasyButton(
                                      label: 'Update Now',
                                      expand: true,
                                      onPressed: () =>
                                          Navigator.of(innerCtx).pop(),
                                    ),
                                    KasyButton(
                                      label: 'Later',
                                      variant: KasyButtonVariant.tertiary,
                                      expand: true,
                                      onPressed: () =>
                                          Navigator.of(innerCtx).pop(),
                                    ),
                                  ],
                                ),
                              ),
                              const SizedBox(height: KasySpacing.sm),
                              _previewIntrinsicLaunch(
                                KasyButton(
                                  label: 'Open dialog',
                                  variant: KasyButtonVariant.soft,
                                  onPressed: () {
                                    showKasyDialog<void>(
                                      context: sheetCtx,
                                      builder: (dialogCtx) => KasyDialog(
                                        leadingIcon: KasyIcons.download,
                                        title: 'Low Disk Space',
                                        message:
                                            'You are running low on disk space. Delete unnecessary files to free up space.',
                                        confirmLabel: 'Confirm',
                                        onConfirm: () {
                                          Navigator.of(dialogCtx).pop();
                                          _triggerTapFeedback();
                                        },
                                      ),
                                    );
                                  },
                                ),
                              ),
                            ],
                          ),
                        ),
                      ),
                    ],
                  ),
                ),
              ),
            ),
          );
        },
      ),
    ),
  );
}

Widget _buildBottomSheetScrollable(BuildContext context) {
  return _BottomSheetTrigger(
    label: 'Open scrollable sheet',
    isScrollControlled: true,
    builder: (sheetCtx) => DraggableScrollableSheet(
      initialChildSize: 0.6,
      minChildSize: 0.4,
      maxChildSize: 0.92,
      expand: false,
      snap: true,
      snapSizes: const [0.6, 0.92],
      builder: (draggableCtx, scrollController) {
        return Container(
          decoration: BoxDecoration(
            color: sheetCtx.colors.surface,
            borderRadius: const BorderRadius.vertical(
              top: Radius.circular(KasyRadius.xl),
            ),
          ),
          child: ListView.builder(
            controller: scrollController,
            padding: EdgeInsets.fromLTRB(
              0,
              0,
              0,
              MediaQuery.paddingOf(draggableCtx).bottom + KasySpacing.lg,
            ),
            itemCount: 8 + 2 + 1,
            itemBuilder: (itemCtx, i) {
              if (i == 0) {
                return Padding(
                  padding: const EdgeInsets.only(top: KasySpacing.smd),
                  child: Center(
                    child: Container(
                      width: 36,
                      height: 4,
                      decoration: BoxDecoration(
                        color: sheetCtx.colors.outline.withValues(alpha: 0.35),
                        borderRadius: BorderRadius.circular(KasyRadius.full),
                      ),
                    ),
                  ),
                );
              }
                  if (i == 1) {
                      return Padding(
                        padding: const EdgeInsets.fromLTRB(
                          KasySpacing.lg,
                          KasySpacing.md,
                          KasySpacing.lg,
                          0,
                        ),
                        child: ClipRRect(
                          borderRadius: BorderRadius.circular(KasyRadius.lg),
                          child: Image.network(
                            'https://picsum.photos/seed/kasy/800/400',
                            height: 200,
                            width: double.infinity,
                            fit: BoxFit.cover,
                            frameBuilder:
                                (ctx, child, frame, wasSynchronouslyLoaded) {
                                  if (wasSynchronouslyLoaded || frame != null) {
                                    return child;
                                  }
                                  return AnimatedSwitcher(
                                    duration: const Duration(milliseconds: 400),
                                    child: frame != null
                                        ? child
                                        : Container(
                                            key: const ValueKey('placeholder'),
                                            height: 200,
                                            decoration: BoxDecoration(
                                              color: sheetCtx
                                                  .colors
                                                  .surfaceNeutralSoft,
                                              borderRadius:
                                                  BorderRadius.circular(
                                                    KasyRadius.lg,
                                                  ),
                                            ),
                                          ),
                                  );
                                },
                          ),
                        ),
                      );
                    }
                    if (i == 2) {
                      return Padding(
                        padding: const EdgeInsets.fromLTRB(
                          KasySpacing.lg,
                          KasySpacing.md,
                          KasySpacing.lg,
                          KasySpacing.sm,
                        ),
                        child: Text(
                          'Terms & Conditions',
                          style: sheetCtx.textTheme.titleLarge?.copyWith(
                            fontWeight: FontWeight.w700,
                            fontSize: 20,
                            color: sheetCtx.colors.onSurface,
                          ),
                        ),
                      );
                    }
                    return Padding(
                      padding: const EdgeInsets.fromLTRB(
                        KasySpacing.lg,
                        0,
                        KasySpacing.lg,
                        KasySpacing.md,
                      ),
                      child: Text(
                        'Section ${i - 2}. Lorem ipsum dolor sit amet consectetur '
                        'adipiscing elit. Sed do eiusmod tempor incididunt ut labore '
                        'et dolore magna aliqua. Ut enim ad minim veniam, quis '
                        'nostrud exercitation ullamco laboris.',
                        style: sheetCtx.textTheme.bodyMedium?.copyWith(
                          color: sheetCtx.colors.onSurface.withValues(
                            alpha: 0.65,
                          ),
                          height: 1.5,
                        ),
                      ),
                    );
                  },
          ),
        );
      },
    ),
  );
}

Widget _buildBottomSheetOtpVerification(BuildContext context) {
  return _BottomSheetTrigger(
    label: 'OTP verification',
    isScrollControlled: true,
    builder: (sheetCtx) =>
        KasyOtpVerificationBottomSheet(sheetContext: sheetCtx),
  );
}

Widget _buildBottomSheetPinVerification(BuildContext context) {
  return _BottomSheetTrigger(
    label: 'PIN verification',
    isScrollControlled: true,
    builder: (sheetCtx) => KasyOtpVerificationBottomSheet(
      sheetContext: sheetCtx,
      preset: KasyOtpVerificationSheetPreset.pinDigits,
    ),
  );
}

class _BottomSheetBlurTrigger extends StatelessWidget {
  final String label;
  final WidgetBuilder builder;

  const _BottomSheetBlurTrigger({required this.label, required this.builder});

  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.symmetric(horizontal: KasySpacing.md),
      child: _previewIntrinsicLaunch(
        KasyButton(
          label: label,
          variant: KasyButtonVariant.soft,
          onPressed: () {
            _triggerTapFeedback();
            showKasyBlurBottomSheet(context: context, builder: builder);
          },
        ),
      ),
    );
  }
}

class _BottomSheetTrigger extends StatelessWidget {
  final String label;
  final WidgetBuilder builder;
  final bool isScrollControlled;

  const _BottomSheetTrigger({
    required this.label,
    required this.builder,
    this.isScrollControlled = false,
  });

  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.symmetric(horizontal: KasySpacing.md),
      child: _previewIntrinsicLaunch(
        KasyButton(
          label: label,
          variant: KasyButtonVariant.soft,
          onPressed: () {
            _triggerTapFeedback();
            showKasyBottomSheet(
              context: context,
              isScrollControlled: isScrollControlled,
              builder: builder,
            );
          },
        ),
      ),
    );
  }
}

// ─── TextFieldOTP builders ───────────────────────────────────────────────────

Widget _buildTextFieldOTPDefault(BuildContext context) {
  return _TextFieldOTPPreviewFrame(
    width: KasyTextFieldOTP.visualWidthFor(separatorAfterIndex: 2),
    child: Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      mainAxisSize: MainAxisSize.min,
      children: [
        Text(
          'Verify account',
          style: context.textTheme.titleMedium?.copyWith(
            fontWeight: FontWeight.w700,
            color: context.colors.onBackground,
          ),
        ),
        const SizedBox(height: 2),
        Text(
          "We've sent a code to a****@gmail.com",
          style: context.textTheme.bodyMedium?.copyWith(
            color: context.colors.muted,
          ),
        ),
        const SizedBox(height: KasySpacing.sm),
        KasyTextFieldOTP(
          separatorAfterIndex: 2,
          onCompleted: (_) => _triggerTapFeedback(),
        ),
        const SizedBox(height: KasySpacing.md),
        Row(
          mainAxisSize: MainAxisSize.min,
          children: [
            Text(
              "Didn't receive a code? ",
              style: context.textTheme.bodyMedium?.copyWith(
                color: context.colors.muted,
              ),
            ),
            const _ResendCodeButton(onTap: _triggerTapFeedback),
          ],
        ),
      ],
    ),
  );
}

Widget _buildTextFieldOTPError(BuildContext context) {
  return const _TextFieldOTPValidationPreview();
}

class _TextFieldOTPValidationPreview extends StatefulWidget {
  const _TextFieldOTPValidationPreview();

  @override
  State<_TextFieldOTPValidationPreview> createState() =>
      _TextFieldOTPValidationPreviewState();
}

class _TextFieldOTPValidationPreviewState
    extends State<_TextFieldOTPValidationPreview> {
  static const String _expectedCode = '123456';

  String _code = '';

  /// Set on each Submit only; stays true while editing until the next Submit clears it.
  bool _showSubmitError = false;

  bool get _hasError => _showSubmitError;

  void _submit() {
    setState(() => _showSubmitError = _code != _expectedCode);
    _triggerTapFeedback();
  }

  @override
  Widget build(BuildContext context) {
    return _TextFieldOTPPreviewFrame(
      width: KasyTextFieldOTP.visualWidthFor(separatorAfterIndex: 2),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        mainAxisSize: MainAxisSize.min,
        children: [
          Text(
            'Verify account',
            style: context.textTheme.titleMedium?.copyWith(
              fontWeight: FontWeight.w700,
              color: _hasError
                  ? context.colors.error
                  : context.colors.onBackground,
            ),
          ),
          const SizedBox(height: 2),
          Text(
            'Hint: The code is 123456',
            style: context.textTheme.bodyMedium?.copyWith(
              color: context.colors.muted,
            ),
          ),
          const SizedBox(height: KasySpacing.sm),
          KasyTextFieldOTP(
            separatorAfterIndex: 2,
            hasError: _hasError,
            onChanged: (value) => setState(() => _code = value),
            onCompleted: (_) => _triggerTapFeedback(),
          ),
          if (_hasError) ...[
            const SizedBox(height: KasySpacing.sm),
            Text(
              'The code you entered is incorrect.',
              style: context.textTheme.titleSmall?.copyWith(
                color: context.colors.error,
                fontWeight: FontWeight.w600,
              ),
            ),
          ],
          SizedBox(height: _hasError ? KasySpacing.lg : KasySpacing.md),
          KasyButton(
            label: 'Submit',
            variant: KasyButtonVariant.soft,
            size: KasyButtonSize.small,
            width: 124,
            onPressed: _submit,
          ),
        ],
      ),
    );
  }
}

Widget _buildTextFieldOTPFourDigits(BuildContext context) {
  return _TextFieldOTPPreviewFrame(
    width: KasyTextFieldOTP.visualWidthFor(length: 4),
    child: Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      mainAxisSize: MainAxisSize.min,
      children: [
        Text(
          'Enter your PIN',
          style: context.textTheme.titleMedium?.copyWith(
            fontWeight: FontWeight.w700,
            color: context.colors.onBackground,
          ),
        ),
        const SizedBox(height: KasySpacing.sm),
        KasyTextFieldOTP(length: 4, onCompleted: (_) => _triggerTapFeedback()),
      ],
    ),
  );
}

Widget _buildTextFieldOTPWithPlaceholder(BuildContext context) {
  return _TextFieldOTPPreviewFrame(
    width: KasyTextFieldOTP.visualWidthFor(separatorAfterIndex: 2),
    child: Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      mainAxisSize: MainAxisSize.min,
      children: [
        Text(
          'Enter verification code',
          style: context.textTheme.titleMedium?.copyWith(
            fontWeight: FontWeight.w700,
            color: context.colors.onBackground,
          ),
        ),
        const SizedBox(height: KasySpacing.sm),
        KasyTextFieldOTP(
          separatorAfterIndex: 2,
          placeholder: '-',
          neutralFlatCells: true,
          onCompleted: (_) => _triggerTapFeedback(),
        ),
      ],
    ),
  );
}

Widget _buildTextFieldOTPDisabled(BuildContext context) {
  return _TextFieldOTPPreviewFrame(
    width: KasyTextFieldOTP.visualWidthFor(separatorAfterIndex: 2),
    child: Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      mainAxisSize: MainAxisSize.min,
      children: [
        Text(
          'Enter verification code',
          style: context.textTheme.titleMedium?.copyWith(
            fontWeight: FontWeight.w700,
            color: context.colors.muted,
          ),
        ),
        const SizedBox(height: KasySpacing.sm),
        const KasyTextFieldOTP(separatorAfterIndex: 2, enabled: false),
      ],
    ),
  );
}

Widget _buildTextFieldOTPWithPattern(BuildContext context) {
  return _TextFieldOTPPreviewFrame(
    width: KasyTextFieldOTP.visualWidthFor(separatorAfterIndex: 2),
    child: Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      mainAxisSize: MainAxisSize.min,
      children: [
        Text(
          'Enter code (letters only)',
          style: context.textTheme.titleMedium?.copyWith(
            fontWeight: FontWeight.w700,
            color: context.colors.onBackground,
          ),
        ),
        const SizedBox(height: 2),
        Text(
          'Only alphabetic characters are allowed',
          style: context.textTheme.bodyMedium?.copyWith(
            color: context.colors.muted,
          ),
        ),
        const SizedBox(height: KasySpacing.sm),
        KasyTextFieldOTP(
          separatorAfterIndex: 2,
          keyboardType: TextInputType.text,
          inputFormatters: [
            FilteringTextInputFormatter.allow(RegExp('[a-zA-Z]')),
          ],
          onCompleted: (_) => _triggerTapFeedback(),
        ),
      ],
    ),
  );
}

Widget _buildTextFieldOTPCustomStyles(BuildContext context) {
  const double gap = 2;
  final double otpWidth = KasyTextFieldOTP.visualWidthFor(
    separatorAfterIndex: 2,
    cellGap: gap,
    separatorStrokeVisible: false,
  );
  const double horizontalInset = KasySpacing.xxl;
  final double frameWidth = otpWidth + horizontalInset * 2;
  return _TextFieldOTPPreviewFrame(
    width: frameWidth,
    child: DecoratedBox(
      decoration: BoxDecoration(
        color: context.colors.surface,
        borderRadius: BorderRadius.circular(KasyRadius.xl),
        border: Border.all(
          color: context.colors.outline.withValues(alpha: 0.22),
        ),
        boxShadow: [KasyShadows.component(context)],
      ),
      child: ClipRRect(
        borderRadius: BorderRadius.circular(KasyRadius.xl),
        child: Padding(
          padding: const EdgeInsets.symmetric(
            horizontal: horizontalInset,
            vertical: KasySpacing.md,
          ),
          child: Center(
            child: KasyTextFieldOTP(
              separatorAfterIndex: 2,
              separatorStrokeVisible: false,
              placeholder: '-',
              cellGap: gap,
              cellFillColor: Colors.transparent,
              suppressCellShadow: true,
              suppressFocusBorder: true,
              onCompleted: (_) => _triggerTapFeedback(),
            ),
          ),
        ),
      ),
    ),
  );
}

Widget _buildTextFieldOTPBottomSheet(BuildContext context) {
  return _previewIntrinsicLaunch(
    KasyButton(
      label: 'Bottom sheet with OTP input',
      variant: KasyButtonVariant.soft,
      onPressed: () {
        _triggerTapFeedback();
        showKasyOtpVerificationBottomSheet<void>(context: context);
      },
    ),
  );
}

class _TextFieldOTPPreviewFrame extends StatelessWidget {
  final double width;
  final Widget child;

  const _TextFieldOTPPreviewFrame({required this.width, required this.child});

  @override
  Widget build(BuildContext context) {
    return LayoutBuilder(
      builder: (context, constraints) {
        final double resolvedWidth =
            constraints.maxWidth.isFinite && constraints.maxWidth < width
            ? constraints.maxWidth
            : width;

        return Center(
          child: SizedBox(width: resolvedWidth, child: child),
        );
      },
    );
  }
}

class _ResendCodeButton extends StatefulWidget {
  final VoidCallback onTap;

  const _ResendCodeButton({required this.onTap});

  @override
  State<_ResendCodeButton> createState() => _ResendCodeButtonState();
}

class _ResendCodeButtonState extends State<_ResendCodeButton> {
  bool _pressed = false;

  Future<void> _handleTap() async {
    setState(() => _pressed = true);
    await KasyHaptics.selection(context);
    await Future<void>.delayed(const Duration(milliseconds: 130));
    if (mounted) setState(() => _pressed = false);
    widget.onTap();
  }

  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      onTap: _handleTap,
      onTapCancel: () => setState(() => _pressed = false),
      child: AnimatedScale(
        scale: _pressed ? 0.93 : 1.0,
        duration: const Duration(milliseconds: 120),
        curve: Curves.easeOutCubic,
        child: AnimatedOpacity(
          opacity: _pressed ? 0.55 : 1.0,
          duration: const Duration(milliseconds: 120),
          child: Text(
            'Resend code',
            style: context.textTheme.bodyMedium?.copyWith(
              color: context.colors.onBackground,
              fontWeight: FontWeight.w700,
            ),
          ),
        ),
      ),
    );
  }
}

// ─── Pressable previews ──────────────────────────────────────────────────────

Widget _buildTappableRowListVariant(BuildContext context) {
  return const _PressableListPreview();
}

Widget _buildTappableRowCardVariant(BuildContext context) {
  return const _PressableButtonsPreview();
}

Widget _buildTappableRowGroupVariant(BuildContext context) {
  return const _PressableCardsPreview();
}

// ─── Variant 1: List rows ────────────────────────────────────────────────────
// Full-bleed rows inside a grouped container — mirrors Settings / Features.
// borderRadius: zero (default); fill covers edge to edge, clipped by the
// outer ClipRRect so the first and last rows respect the container corners.

class _PressableListItem {
  final IconData icon;
  final String title;
  final String subtitle;
  const _PressableListItem({
    required this.icon,
    required this.title,
    required this.subtitle,
  });
}

const List<_PressableListItem> _kPressableListItems = [
  _PressableListItem(
    icon: KasyIcons.notification,
    title: 'Notifications',
    subtitle: 'App alerts and reminders',
  ),
  _PressableListItem(
    icon: KasyIcons.payment,
    title: 'Subscription',
    subtitle: 'Plans and payment history',
  ),
  _PressableListItem(
    icon: KasyIcons.assistant,
    title: 'Assistant',
    subtitle: 'AI assistant preferences',
  ),
];

class _PressableListPreview extends StatelessWidget {
  const _PressableListPreview();

  @override
  Widget build(BuildContext context) {
    return DecoratedBox(
      decoration: BoxDecoration(
        color: context.colors.surface,
        borderRadius: BorderRadius.circular(KasyRadius.lg),
        border: Border.all(
          color: context.colors.outline.withValues(alpha: 0.4),
        ),
      ),
      child: ClipRRect(
        borderRadius: BorderRadius.circular(KasyRadius.lg),
        child: Column(
          mainAxisSize: MainAxisSize.min,
          children: [
            for (int i = 0; i < _kPressableListItems.length; i++) ...[
              KasyHover(
                onTap: () => KasyHaptics.selection(context),
                padding: const EdgeInsets.symmetric(
                  horizontal: KasySpacing.smd,
                  vertical: 14,
                ),
                semanticLabel: _kPressableListItems[i].title,
                child: Row(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    DecoratedBox(
                      decoration: BoxDecoration(
                        color: context.colors.primary.withValues(alpha: 0.12),
                        borderRadius: BorderRadius.circular(KasyRadius.md),
                      ),
                      child: SizedBox(
                        width: 40,
                        height: 40,
                        child: Icon(
                          _kPressableListItems[i].icon,
                          size: 20,
                          color: context.colors.primary,
                        ),
                      ),
                    ),
                    const SizedBox(width: KasySpacing.smd),
                    Expanded(
                      child: Column(
                        crossAxisAlignment: CrossAxisAlignment.start,
                        children: [
                          Text(
                            _kPressableListItems[i].title,
                            style: context.textTheme.bodyLarge?.copyWith(
                              fontWeight: FontWeight.w600,
                              color: context.colors.onSurface,
                            ),
                          ),
                          const SizedBox(height: 3),
                          Text(
                            _kPressableListItems[i].subtitle,
                            style: context.textTheme.bodySmall?.copyWith(
                              color: context.colors.muted,
                            ),
                          ),
                        ],
                      ),
                    ),
                    Padding(
                      padding: const EdgeInsets.only(
                        left: KasySpacing.xs,
                        top: 8,
                      ),
                      child: Icon(
                        KasyIcons.chevronRight,
                        color: context.colors.muted,
                        size: 20,
                      ),
                    ),
                  ],
                ),
              ),
              if (i < _kPressableListItems.length - 1)
                Divider(
                  height: 1,
                  thickness: 1,
                  indent: KasySpacing.smd,
                  color: context.colors.outline.withValues(alpha: 0.33),
                ),
            ],
          ],
        ),
      ),
    );
  }
}

// ─── Variant 2: Custom buttons ───────────────────────────────────────────────
// Different button shapes — outlined pill, tonal pill, icon-grid.
class _PressableButtonsPreview extends StatelessWidget {
  const _PressableButtonsPreview();

  static const BorderRadius _pillRadius =
      BorderRadius.all(Radius.circular(KasyRadius.full));

  @override
  Widget build(BuildContext context) {
    return Column(
      mainAxisSize: MainAxisSize.min,
      crossAxisAlignment: CrossAxisAlignment.stretch,
      children: [
        KasyButton(
          label: 'View plans',
          icon: KasyIcons.payment,
          variant: KasyButtonVariant.outline,
          pressEffect: KasyButtonPressEffect.fill,
          backgroundColor: context.colors.surface,
          borderRadius: _pillRadius,
          expand: true,
          onPressed: _noop,
        ),
        const SizedBox(height: KasySpacing.sm),
        KasyButton(
          label: 'Subscribe now',
          icon: KasyIcons.star,
          variant: KasyButtonVariant.soft,
          pressEffect: KasyButtonPressEffect.fill,
          backgroundColor: context.colors.primary.withValues(alpha: 0.10),
          borderColor: context.colors.primary.withValues(alpha: 0.25),
          borderRadius: _pillRadius,
          expand: true,
          onPressed: _noop,
        ),
      ],
    );
  }
}

class _HoverIconGrid extends StatelessWidget {
  const _HoverIconGrid();

  @override
  Widget build(BuildContext context) {
    return Row(
      children: [
        for (final (IconData icon, String label) in <(IconData, String)>[
          (KasyIcons.gallery, 'Gallery'),
          (KasyIcons.message, 'Message'),
          (KasyIcons.notification, 'Alerts'),
        ])
          Expanded(
            child: Padding(
              padding: const EdgeInsets.symmetric(horizontal: KasySpacing.xs),
              child: KasyCard(
                variant: KasyCardVariant.outlined,
                color: context.colors.surface,
                borderRadius: KasyRadius.mdBorderRadius,
                child: KasyHover(
                  onTap: _noop,
                  semanticLabel: label,
                  padding: const EdgeInsets.symmetric(vertical: 14),
                  child: Column(
                    mainAxisSize: MainAxisSize.min,
                    children: [
                      Icon(icon, size: 22, color: context.colors.onSurface),
                      const SizedBox(height: 6),
                      Text(
                        label,
                        style: context.textTheme.labelMedium?.copyWith(
                          color: context.colors.onSurface,
                        ),
                      ),
                    ],
                  ),
                ),
              ),
            ),
          ),
      ],
    );
  }
}

// ─── Variant 3: Clickable cards ──────────────────────────────────────────────
// KasyCard with onTap — the card handles interaction via KasyPressableDepth.

class _PressableCardsPreview extends StatelessWidget {
  const _PressableCardsPreview();

  @override
  Widget build(BuildContext context) {
    return Column(
      mainAxisSize: MainAxisSize.min,
      children: [
        KasyCard(
          variant: KasyCardVariant.outlined,
          color: context.colors.primary.withValues(alpha: 0.08),
          borderColor: context.colors.primary.withValues(alpha: 0.25),
          borderRadius: KasyRadius.lgBorderRadius,
          child: KasyHover(
            onTap: _noop,
            pressColor: context.colors.primary,
            padding: const EdgeInsets.all(KasySpacing.md),
            child: Row(
              children: [
                DecoratedBox(
                  decoration: BoxDecoration(
                    color: context.colors.primary.withValues(alpha: 0.15),
                    borderRadius: BorderRadius.circular(KasyRadius.md),
                  ),
                  child: SizedBox(
                    width: 48,
                    height: 48,
                    child: Icon(
                      KasyIcons.star,
                      size: 24,
                      color: context.colors.primary,
                    ),
                  ),
                ),
                const SizedBox(width: KasySpacing.smd),
                Expanded(
                  child: Column(
                    crossAxisAlignment: CrossAxisAlignment.start,
                    children: [
                      Text(
                        'Explore premium',
                        style: context.textTheme.titleSmall?.copyWith(
                          fontWeight: FontWeight.w700,
                        ),
                      ),
                      const SizedBox(height: 3),
                      Text(
                        'Unlock all features without limits',
                        style: context.textTheme.bodySmall?.copyWith(
                          color: context.colors.muted,
                        ),
                      ),
                    ],
                  ),
                ),
                Icon(
                  KasyIcons.chevronRight,
                  color: context.colors.primary,
                  size: 20,
                ),
              ],
            ),
          ),
        ),
        const SizedBox(height: KasySpacing.sm),
        Row(
          children: [
            for (final (IconData icon, String title, String desc)
                in <(IconData, String, String)>[
              (KasyIcons.assistant, 'AI Chat', 'Smart conversations'),
              (KasyIcons.gallery, 'Gallery', 'Browse photos'),
            ])
              Expanded(
                child: Padding(
                  padding: const EdgeInsets.symmetric(
                    horizontal: KasySpacing.xs,
                  ),
                  child: KasyCard(
                    variant: KasyCardVariant.outlined,
                    color: context.colors.surface,
                    borderRadius: KasyRadius.lgBorderRadius,
                    child: KasyHover(
                      onTap: _noop,
                      padding: const EdgeInsets.all(KasySpacing.smd),
                      child: Column(
                        crossAxisAlignment: CrossAxisAlignment.start,
                        children: [
                          Icon(icon, size: 22, color: context.colors.primary),
                          const SizedBox(height: KasySpacing.sm),
                          Text(
                            title,
                            style: context.textTheme.titleSmall?.copyWith(
                              fontWeight: FontWeight.w700,
                            ),
                          ),
                          const SizedBox(height: 2),
                          Text(
                            desc,
                            style: context.textTheme.bodySmall?.copyWith(
                              color: context.colors.muted,
                            ),
                          ),
                        ],
                      ),
                    ),
                  ),
                ),
              ),
          ],
        ),
        const SizedBox(height: KasySpacing.sm),
        const _HoverIconGrid(),
      ],
    );
  }
}

// ---------------------------------------------------------------------------
// Checkbox previews
// ---------------------------------------------------------------------------

Widget _buildCheckboxBasicUsage(BuildContext context) =>
    const _CheckboxBasicPreview();

Widget _buildCheckboxStates(BuildContext context) =>
    const _CheckboxStatesPreview();

Widget _buildCheckboxCustomStyles(BuildContext context) =>
    const _CheckboxCustomStylesPreview();

// — Basic usage —

class _CheckboxBasicPreview extends StatefulWidget {
  const _CheckboxBasicPreview();

  @override
  State<_CheckboxBasicPreview> createState() => _CheckboxBasicPreviewState();
}

class _CheckboxBasicPreviewState extends State<_CheckboxBasicPreview> {
  bool _newsletter = true;
  bool _marketing = false;
  bool _terms = false;

  @override
  Widget build(BuildContext context) {
    return DecoratedBox(
      decoration: BoxDecoration(
        color: context.colors.surface,
        borderRadius: KasyRadius.lgBorderRadius,
        border: Border.all(
          color: context.colors.outline.withValues(alpha: 0.4),
        ),
      ),
      child: Column(
        mainAxisSize: MainAxisSize.min,
        children: [
          KasyCheckboxTile(
            value: _newsletter,
            onChanged: (v) => setState(() => _newsletter = v),
            label: 'Subscribe to newsletter',
            description: 'Get weekly updates about new features and tips',
          ),
          Divider(
            height: 1,
            thickness: 1,
            indent: KasySpacing.md,
            endIndent: KasySpacing.md,
            color: context.colors.outline.withValues(alpha: 0.33),
          ),
          KasyCheckboxTile(
            value: _marketing,
            onChanged: (v) => setState(() => _marketing = v),
            label: 'Marketing communications',
            description: 'Receive promotional emails and special offers',
          ),
          Divider(
            height: 1,
            thickness: 1,
            indent: KasySpacing.md,
            endIndent: KasySpacing.md,
            color: context.colors.outline.withValues(alpha: 0.33),
          ),
          KasyCheckboxTile(
            value: _terms,
            onChanged: (v) => setState(() => _terms = v),
            label: 'Accept terms and conditions',
            description: 'Agree to our Terms of Service and Privacy Policy',
          ),
        ],
      ),
    );
  }
}

// — States —

class _CheckboxStatesPreview extends StatefulWidget {
  const _CheckboxStatesPreview();

  @override
  State<_CheckboxStatesPreview> createState() => _CheckboxStatesPreviewState();
}

class _CheckboxStatesPreviewState extends State<_CheckboxStatesPreview> {
  bool _default = true;
  bool _invalid = true;

  @override
  Widget build(BuildContext context) {
    final TextStyle labelStyle =
        context.textTheme.labelSmall?.copyWith(
          color: context.colors.muted,
          letterSpacing: 1.1,
          fontWeight: FontWeight.w600,
        ) ??
        const TextStyle();

    Widget labeled(String l, Widget checkbox) => Column(
          mainAxisSize: MainAxisSize.min,
          children: [
            checkbox,
            const SizedBox(height: KasySpacing.sm),
            Text(l, style: labelStyle),
          ],
        );

    return Row(
      mainAxisAlignment: MainAxisAlignment.center,
      children: [
        labeled(
          'Default',
          KasyCheckbox(
            value: _default,
            onChanged: (v) => setState(() => _default = v),
          ),
        ),
        const SizedBox(width: KasySpacing.xl),
        labeled(
          'Invalid',
          KasyCheckbox(
            value: _invalid,
            isInvalid: true,
            onChanged: (v) => setState(() => _invalid = v),
          ),
        ),
        const SizedBox(width: KasySpacing.xl),
        labeled(
          'Disabled',
          const KasyCheckbox(value: true),
        ),
      ],
    );
  }
}

// — Custom styles —

class _CheckboxCustomStylesPreview extends StatefulWidget {
  const _CheckboxCustomStylesPreview();

  @override
  State<_CheckboxCustomStylesPreview> createState() =>
      _CheckboxCustomStylesPreviewState();
}

class _CheckboxCustomStylesPreviewState
    extends State<_CheckboxCustomStylesPreview> {
  bool _fav = false;
  bool _notif = true;
  bool _done = true;

  // Style 1 — favorite: no bg, outline heart ↔ filled heart, red icon
  static const KasyCheckboxStyle _favStyle = KasyCheckboxStyle(
    size: 26,
    activeColor: Colors.transparent,
    inactiveColor: Colors.transparent,
    borderColor: Colors.transparent,
    checkedIcon: KasyIcons.favoriteFilled,
    uncheckedIcon: KasyIcons.favorite,
    checkColor: Color(0xFFEF4444),
    borderWidth: 0,
  );

  @override
  Widget build(BuildContext context) {
    // Style 2 — notification on/off: always filled, bell swaps
    final Color notifInactive = context.isDark
        ? const Color(0xFF475569)
        : const Color(0xFF94A3B8);

    final KasyCheckboxStyle notifStyle = KasyCheckboxStyle(
      size: 28,
      activeColor: const Color(0xFFF59E0B),
      inactiveColor: notifInactive,
      borderColor: Colors.transparent,
      checkedIcon: KasyIcons.notificationActive,
      uncheckedIcon: KasyIcons.notificationOff,
      checkColor: Colors.white,
      borderWidth: 0,
    );

    // Style 3 — approve/deny: red X (off) → green check (on)
    const KasyCheckboxStyle doneStyle = KasyCheckboxStyle(
      size: 52,
      shape: KasyCheckboxShape.circle,
      activeColor: Color(0xFF10B981),
      inactiveColor: Color(0xFFEF4444),
      borderColor: Colors.transparent,
      checkedIcon: KasyIcons.check,
      uncheckedIcon: KasyIcons.close,
      checkColor: Colors.white,
      borderWidth: 0,
    );

    return Row(
      mainAxisAlignment: MainAxisAlignment.center,
      children: [
        KasyCheckbox(
          value: _fav,
          onChanged: (v) => setState(() => _fav = v),
          style: _favStyle,
        ),
        const SizedBox(width: KasySpacing.xl),
        KasyCheckbox(
          value: _notif,
          onChanged: (v) => setState(() => _notif = v),
          style: notifStyle,
        ),
        const SizedBox(width: KasySpacing.xl),
        KasyCheckbox(
          value: _done,
          onChanged: (v) => setState(() => _done = v),
          style: doneStyle,
        ),
      ],
    );
  }
}

// ─── Skeleton preview ─────────────────────────────────────────────────────────

const String _kUnsplashCard =
    'https://images.unsplash.com/photo-1506905925346-21bda4d32df4'
    '?w=600&q=80&fit=crop';

class _SkeletonCardPreview extends StatefulWidget {
  const _SkeletonCardPreview();

  @override
  State<_SkeletonCardPreview> createState() => _SkeletonCardPreviewState();
}

class _SkeletonCardPreviewState extends State<_SkeletonCardPreview> {
  KasySkeletonAnimation _mode = KasySkeletonAnimation.shimmer;
  bool _loading = true;

  @override
  Widget build(BuildContext context) {
    return Column(
      crossAxisAlignment: CrossAxisAlignment.stretch,
      children: [
        _buildCard(context),
        const SizedBox(height: KasySpacing.lg),
        _buildControls(context),
      ],
    );
  }

  // ── Card ───────────────────────────────────────────────────────────────────
  // Stack + AnimatedOpacity: both cards are in the layout simultaneously,
  // so the column height never changes → controls below never shift.

  Widget _buildCard(BuildContext context) {
    return Stack(
      children: [
        // Real card — always rendered so the image preloads.
        AnimatedOpacity(
          opacity: _loading ? 0.0 : 1.0,
          duration: const Duration(milliseconds: 260),
          curve: Curves.easeOut,
          child: const _RealCardContent(),
        ),
        // Skeleton — fades out on top.
        IgnorePointer(
          ignoring: !_loading,
          child: AnimatedOpacity(
            opacity: _loading ? 1.0 : 0.0,
            duration: const Duration(milliseconds: 200),
            curve: Curves.easeIn,
            child: KasySkeletonGroup(
              animation: _mode,
              child: const _SkeletonCardContent(),
            ),
          ),
        ),
      ],
    );
  }

  // ── Controls ───────────────────────────────────────────────────────────────

  Widget _buildControls(BuildContext context) {
    return _SkeletonControls(
      mode: _mode,
      loading: _loading,
      onModeChanged: (m) => setState(() => _mode = m),
      onLoadingChanged: (v) => setState(() => _loading = v),
    );
  }
}

// ── Skeleton card content ──────────────────────────────────────────────────────
// Layout mirrors _RealCardContent exactly so the Stack height stays constant.

class _SkeletonCardContent extends StatelessWidget {
  const _SkeletonCardContent();

  @override
  Widget build(BuildContext context) {
    return const KasyCard(
      child: Padding(
        padding: EdgeInsets.all(KasySpacing.md),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            // ① Author row
            Row(
              children: [
                KasySkeleton.circle(size: 40),
                SizedBox(width: KasySpacing.smd),
                Flexible(
                  child: Column(
                    crossAxisAlignment: CrossAxisAlignment.start,
                    children: [
                      KasySkeleton(width: 120, height: 13),
                      SizedBox(height: KasySpacing.xs),
                      KasySkeleton(width: 80, height: 11),
                    ],
                  ),
                ),
              ],
            ),
            SizedBox(height: KasySpacing.smd),
            // ② Image placeholder
            KasySkeleton(
              width: double.infinity,
              height: 180,
              borderRadius: BorderRadius.all(Radius.circular(KasyRadius.md)),
            ),
            SizedBox(height: KasySpacing.smd),
            // ③ Caption lines  (3 lines ≈ same height as real Text)
            KasySkeleton(width: double.infinity, height: 11),
            SizedBox(height: KasySpacing.xs),
            KasySkeleton(width: double.infinity, height: 11),
            SizedBox(height: KasySpacing.xs),
            KasySkeleton(width: 160, height: 11),
            SizedBox(height: KasySpacing.md),
            // ④ Action buttons
            Row(
              children: [
                KasySkeleton(
                  width: 88,
                  height: 34,
                  borderRadius: BorderRadius.all(Radius.circular(KasyRadius.sm)),
                ),
                SizedBox(width: KasySpacing.sm),
                KasySkeleton(
                  width: 88,
                  height: 34,
                  borderRadius: BorderRadius.all(Radius.circular(KasyRadius.sm)),
                ),
              ],
            ),
          ],
        ),
      ),
    );
  }
}

// ── Real card content ──────────────────────────────────────────────────────────

class _RealCardContent extends StatelessWidget {
  const _RealCardContent();

  @override
  Widget build(BuildContext context) {
    final c = context.colors;

    return KasyCard(
      child: Padding(
        padding: const EdgeInsets.all(KasySpacing.md),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            // ① Author row
            Row(
              children: [
                const KasyAvatar(
                  size: KasyAvatarSize.small,
                  initials: 'AJ',
                ),
                const SizedBox(width: KasySpacing.smd),
                Expanded(
                  child: Column(
                    crossAxisAlignment: CrossAxisAlignment.start,
                    children: [
                      Text(
                        'Alex Johnson',
                        style: TextStyle(
                          fontSize: 14,
                          fontWeight: FontWeight.w600,
                          color: c.onSurface,
                        ),
                      ),
                      Text(
                        '@alexjohnson · 2h ago',
                        style: TextStyle(fontSize: 12, color: c.muted),
                      ),
                    ],
                  ),
                ),
              ],
            ),
            const SizedBox(height: KasySpacing.smd),
            // ② Photo — full-width, rounded, sits between header and caption
            ClipRRect(
              borderRadius: KasyRadius.mdBorderRadius,
              child: SizedBox(
                width: double.infinity,
                height: 180,
                child: Image.network(
                  _kUnsplashCard,
                  fit: BoxFit.cover,
                  loadingBuilder: (context, child, loadingProgress) {
                    if (loadingProgress == null) return child;
                    return ColoredBox(
                      color: c.surfaceNeutralSoft,
                      child: Center(
                        child: CircularProgressIndicator(
                          color: c.primary,
                          strokeWidth: 2,
                          value: loadingProgress.expectedTotalBytes != null
                              ? loadingProgress.cumulativeBytesLoaded /
                                  loadingProgress.expectedTotalBytes!
                              : null,
                        ),
                      ),
                    );
                  },
                  errorBuilder: (context, error, stackTrace) => ColoredBox(
                    color: c.surfaceNeutralSoft,
                    child: Center(
                      child: Icon(KasyIcons.gallery, size: 32, color: c.muted),
                    ),
                  ),
                ),
              ),
            ),
            const SizedBox(height: KasySpacing.smd),
            // ③ Caption
            Text(
              'Breathtaking view from the summit trail in Patagonia. '
              'Golden hour light made every single step worth it.',
              maxLines: 3,
              overflow: TextOverflow.ellipsis,
              style: TextStyle(
                fontSize: 13,
                color: c.onSurface,
                height: 1.5,
              ),
            ),
            const SizedBox(height: KasySpacing.md),
            // ④ Action buttons
            Row(
              children: [
                KasyButton(
                  label: 'Like',
                  icon: KasyIcons.favorite,
                  variant: KasyButtonVariant.neutral,
                  size: KasyButtonSize.small,
                  onPressed: () {},
                ),
                const SizedBox(width: KasySpacing.sm),
                KasyButton(
                  label: 'Share',
                  icon: KasyIcons.share,
                  variant: KasyButtonVariant.neutral,
                  size: KasyButtonSize.small,
                  onPressed: () {},
                ),
              ],
            ),
          ],
        ),
      ),
    );
  }
}

// ─── Shared skeleton controls ─────────────────────────────────────────────────

class _SkeletonControls extends StatelessWidget {
  const _SkeletonControls({
    required this.mode,
    required this.loading,
    required this.onModeChanged,
    required this.onLoadingChanged,
  });

  final KasySkeletonAnimation mode;
  final bool loading;
  final ValueChanged<KasySkeletonAnimation> onModeChanged;
  final ValueChanged<bool> onLoadingChanged;

  @override
  Widget build(BuildContext context) {
    final c = context.colors;

    return KasyCard(
      variant: KasyCardVariant.outlined,
      child: Padding(
        padding: const EdgeInsets.symmetric(
          horizontal: KasySpacing.md,
          vertical: KasySpacing.smd,
        ),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            // Label
            Text(
              'Animation',
              style: TextStyle(
                fontSize: 12,
                fontWeight: FontWeight.w600,
                color: c.muted,
                letterSpacing: 0.4,
              ),
            ),
            const SizedBox(height: KasySpacing.sm),
            // Mode buttons
            Row(
              children: KasySkeletonAnimation.values.map((m) {
                final selected = mode == m;
                final label = switch (m) {
                  KasySkeletonAnimation.shimmer => 'Shimmer',
                  KasySkeletonAnimation.pulse => 'Pulse',
                  KasySkeletonAnimation.none => 'None',
                };
                return Expanded(
                  child: Padding(
                    padding: EdgeInsets.only(
                      right: m != KasySkeletonAnimation.none
                          ? KasySpacing.xs
                          : 0,
                    ),
                    child: KasyButton(
                      label: label,
                      variant: selected
                          ? KasyButtonVariant.primary
                          : KasyButtonVariant.neutral,
                      size: KasyButtonSize.small,
                      onPressed: () => onModeChanged(m),
                    ),
                  ),
                );
              }).toList(),
            ),
            const SizedBox(height: KasySpacing.smd),
            Divider(
              height: 1,
              thickness: 1,
              color: c.outline.withValues(alpha: 0.28),
            ),
            const SizedBox(height: KasySpacing.smd),
            // Loading toggle row
            Row(
              children: [
                Container(
                  width: 30,
                  height: 30,
                  decoration: BoxDecoration(
                    color: c.primary.withValues(alpha: 0.12),
                    borderRadius: BorderRadius.circular(KasyRadius.sm),
                  ),
                  child: Icon(KasyIcons.refresh, size: 16, color: c.primary),
                ),
                const SizedBox(width: KasySpacing.sm),
                Expanded(
                  child: Column(
                    crossAxisAlignment: CrossAxisAlignment.start,
                    children: [
                      Text(
                        'Loading',
                        style: context.textTheme.titleMedium
                            ?.copyWith(color: c.onSurface),
                      ),
                      Text(
                        'Toggle skeleton loading state',
                        style: TextStyle(fontSize: 11, color: c.muted),
                      ),
                    ],
                  ),
                ),
                Transform.scale(
                  scale: 0.82,
                  child: Switch.adaptive(
                    value: loading,
                    onChanged: onLoadingChanged,
                    materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
                  ),
                ),
              ],
            ),
          ],
        ),
      ),
    );
  }
}

// ─── List skeleton preview ────────────────────────────────────────────────────

class _SkeletonListPreview extends StatefulWidget {
  const _SkeletonListPreview();

  @override
  State<_SkeletonListPreview> createState() => _SkeletonListPreviewState();
}

class _SkeletonListPreviewState extends State<_SkeletonListPreview> {
  KasySkeletonAnimation _mode = KasySkeletonAnimation.shimmer;
  bool _loading = true;

  static const List<({String title, String subtitle, IconData icon, Color color})>
      _kItems = [
    (
      title: 'Notifications',
      subtitle: 'Push, email and in-app alerts',
      icon: KasyIcons.notification,
      color: Color(0xFF5C6BC0),
    ),
    (
      title: 'Privacy',
      subtitle: 'Manage data and permissions',
      icon: KasyIcons.privacy,
      color: Color(0xFF26A69A),
    ),
    (
      title: 'Appearance',
      subtitle: 'Theme, font size and display',
      icon: KasyIcons.palette,
      color: Color(0xFFFFA726),
    ),
    (
      title: 'Storage',
      subtitle: 'Cache, media and backups',
      icon: KasyIcons.packageOutline,
      color: Color(0xFFEF5350),
    ),
  ];

  @override
  Widget build(BuildContext context) {
    return Column(
      crossAxisAlignment: CrossAxisAlignment.stretch,
      children: [
        _buildList(context),
        const SizedBox(height: KasySpacing.lg),
        _SkeletonControls(
          mode: _mode,
          loading: _loading,
          onModeChanged: (m) => setState(() => _mode = m),
          onLoadingChanged: (v) => setState(() => _loading = v),
        ),
      ],
    );
  }

  Widget _buildList(BuildContext context) {
    return Stack(
      children: [
        // Real list — always rendered
        AnimatedOpacity(
          opacity: _loading ? 0.0 : 1.0,
          duration: const Duration(milliseconds: 260),
          curve: Curves.easeOut,
          child: _buildRealList(context),
        ),
        // Skeleton — fades out
        IgnorePointer(
          ignoring: !_loading,
          child: AnimatedOpacity(
            opacity: _loading ? 1.0 : 0.0,
            duration: const Duration(milliseconds: 200),
            curve: Curves.easeIn,
            child: KasySkeletonGroup(
              animation: _mode,
              child: _buildSkeletonList(),
            ),
          ),
        ),
      ],
    );
  }

  Widget _buildSkeletonList() {
    return KasyCard(
      child: Column(
        children: List.generate(_kItems.length, (i) {
          return _SkeletonListRow(index: i, isLast: i == _kItems.length - 1);
        }),
      ),
    );
  }

  Widget _buildRealList(BuildContext context) {
    final c = context.colors;

    return KasyCard(
      child: Column(
        children: List.generate(_kItems.length, (i) {
          final item = _kItems[i];
          final isLast = i == _kItems.length - 1;
          return Column(
            children: [
              Padding(
                padding: const EdgeInsets.symmetric(
                  horizontal: KasySpacing.md,
                  vertical: KasySpacing.smd,
                ),
                child: Row(
                  children: [
                    Container(
                      width: 44,
                      height: 44,
                      decoration: BoxDecoration(
                        color: item.color.withValues(alpha: 0.14),
                        borderRadius: KasyRadius.smBorderRadius,
                      ),
                      child: Icon(item.icon, size: 20, color: item.color),
                    ),
                    const SizedBox(width: KasySpacing.smd),
                    Expanded(
                      child: Column(
                        crossAxisAlignment: CrossAxisAlignment.start,
                        children: [
                          Text(
                            item.title,
                            style: TextStyle(
                              fontSize: 14,
                              fontWeight: FontWeight.w600,
                              color: c.onSurface,
                            ),
                          ),
                          Text(
                            item.subtitle,
                            style: TextStyle(fontSize: 12, color: c.muted),
                          ),
                        ],
                      ),
                    ),
                    Icon(
                      KasyIcons.chevronRight,
                      size: 18,
                      color: c.muted,
                    ),
                  ],
                ),
              ),
              if (!isLast)
                Divider(
                  height: 1,
                  indent: KasySpacing.md + 44 + KasySpacing.smd,
                  color: context.colors.outline.withValues(alpha: 0.22),
                ),
            ],
          );
        }),
      ),
    );
  }
}

// ── Skeleton list row ──────────────────────────────────────────────────────────

class _SkeletonListRow extends StatelessWidget {
  const _SkeletonListRow({required this.index, required this.isLast});

  final int index;
  final bool isLast;

  // Vary subtitle widths per row for a realistic look.
  static const List<double> _subtitleWidths = [160, 140, 170, 130];

  @override
  Widget build(BuildContext context) {
    final subtitleW = _subtitleWidths[index % _subtitleWidths.length];

    return Column(
      children: [
        Padding(
          padding: const EdgeInsets.symmetric(
            horizontal: KasySpacing.md,
            vertical: KasySpacing.smd,
          ),
          child: Row(
            children: [
              const KasySkeleton(
                width: 44,
                height: 44,
                borderRadius: BorderRadius.all(Radius.circular(KasyRadius.sm)),
              ),
              const SizedBox(width: KasySpacing.smd),
              Expanded(
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    const KasySkeleton(width: double.infinity, height: 13),
                    const SizedBox(height: KasySpacing.xs),
                    KasySkeleton(width: subtitleW, height: 11),
                  ],
                ),
              ),
            ],
          ),
        ),
        if (!isLast)
          Divider(
            height: 1,
            indent: KasySpacing.md + 44 + KasySpacing.smd,
            color: context.colors.outline.withValues(alpha: 0.22),
          ),
      ],
    );
  }
}

// ─── Text skeleton preview ────────────────────────────────────────────────────

class _SkeletonTextPreview extends StatefulWidget {
  const _SkeletonTextPreview();

  @override
  State<_SkeletonTextPreview> createState() => _SkeletonTextPreviewState();
}

class _SkeletonTextPreviewState extends State<_SkeletonTextPreview> {
  KasySkeletonAnimation _mode = KasySkeletonAnimation.shimmer;
  bool _loading = true;

  static const String _kParagraph =
      'The new productivity dashboard makes it easy to track daily tasks '
      'and goals. You can customize widgets and set smart reminders.';

  @override
  Widget build(BuildContext context) {
    return Column(
      crossAxisAlignment: CrossAxisAlignment.stretch,
      children: [
        _buildContent(context),
        const SizedBox(height: KasySpacing.lg),
        _SkeletonControls(
          mode: _mode,
          loading: _loading,
          onModeChanged: (m) => setState(() => _mode = m),
          onLoadingChanged: (v) => setState(() => _loading = v),
        ),
      ],
    );
  }

  Widget _buildContent(BuildContext context) {
    return Stack(
      children: [
        // Real text — always rendered to fix the height.
        AnimatedOpacity(
          opacity: _loading ? 0.0 : 1.0,
          duration: const Duration(milliseconds: 260),
          curve: Curves.easeOut,
          child: _buildRealText(context),
        ),
        // Skeleton lines on top.
        IgnorePointer(
          ignoring: !_loading,
          child: AnimatedOpacity(
            opacity: _loading ? 1.0 : 0.0,
            duration: const Duration(milliseconds: 200),
            curve: Curves.easeIn,
            child: KasySkeletonGroup(
              animation: _mode,
              child: const _SkeletonTextBlock(),
            ),
          ),
        ),
      ],
    );
  }

  Widget _buildRealText(BuildContext context) {
    return Text(
      _kParagraph,
      style: TextStyle(
        fontSize: 16,
        height: 1.6,
        color: context.colors.onSurface,
      ),
    );
  }
}

// ── Skeleton text block ────────────────────────────────────────────────────────
// Three lines mimicking a paragraph: 100% → ~68% → ~42% width.

class _SkeletonTextBlock extends StatelessWidget {
  const _SkeletonTextBlock();

  @override
  Widget build(BuildContext context) {
    // Line height matches real Text(fontSize:16, height:1.6) → 25.6px per line.
    // Bone height 14px + gap 11px ≈ 25px between baselines.
    return const Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        KasySkeleton(width: double.infinity, height: 14),
        SizedBox(height: 11),
        KasySkeleton(width: double.infinity, height: 14),
        SizedBox(height: 11),
        KasySkeleton(width: double.infinity, height: 14),
        SizedBox(height: 11),
        KasySkeleton(width: double.infinity, height: 14),
        SizedBox(height: 11),
        KasySkeleton(width: 160, height: 14),
      ],
    );
  }
}

// ─── Profile skeleton preview ─────────────────────────────────────────────────

class _SkeletonProfilePreview extends StatefulWidget {
  const _SkeletonProfilePreview();

  @override
  State<_SkeletonProfilePreview> createState() =>
      _SkeletonProfilePreviewState();
}

class _SkeletonProfilePreviewState extends State<_SkeletonProfilePreview> {
  KasySkeletonAnimation _mode = KasySkeletonAnimation.shimmer;
  bool _loading = true;

  @override
  Widget build(BuildContext context) {
    return Column(
      crossAxisAlignment: CrossAxisAlignment.stretch,
      children: [
        _buildContent(context),
        const SizedBox(height: KasySpacing.lg),
        _SkeletonControls(
          mode: _mode,
          loading: _loading,
          onModeChanged: (m) => setState(() => _mode = m),
          onLoadingChanged: (v) => setState(() => _loading = v),
        ),
      ],
    );
  }

  Widget _buildContent(BuildContext context) {
    return Stack(
      children: [
        AnimatedOpacity(
          opacity: _loading ? 0.0 : 1.0,
          duration: const Duration(milliseconds: 260),
          curve: Curves.easeOut,
          child: _buildRealProfile(context),
        ),
        IgnorePointer(
          ignoring: !_loading,
          child: AnimatedOpacity(
            opacity: _loading ? 1.0 : 0.0,
            duration: const Duration(milliseconds: 200),
            curve: Curves.easeIn,
            child: KasySkeletonGroup(
              animation: _mode,
              child: const _SkeletonProfileBlock(),
            ),
          ),
        ),
      ],
    );
  }

  Widget _buildRealProfile(BuildContext context) {
    final c = context.colors;

    return Column(
      children: [
        // Avatar
        const KasyAvatar(
          size: KasyAvatarSize.large,
          initials: 'AJ',
        ),
        const SizedBox(height: KasySpacing.smd),
        // Name
        Text(
          'Alex Johnson',
          style: TextStyle(
            fontSize: 20,
            fontWeight: FontWeight.w700,
            color: c.onSurface,
          ),
        ),
        const SizedBox(height: KasySpacing.xs),
        // Handle
        Text(
          '@alexjohnson',
          style: TextStyle(fontSize: 13, color: c.muted),
        ),
        const SizedBox(height: KasySpacing.smd),
        // Bio
        Text(
          'Product designer & outdoor enthusiast. Building tools that help people do more with less.',
          textAlign: TextAlign.center,
          style: TextStyle(fontSize: 13, color: c.onSurface, height: 1.5),
        ),
        const SizedBox(height: KasySpacing.md),
        // Stats row
        const Row(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            _StatCell(label: 'Posts', value: '142'),
            _StatDivider(),
            _StatCell(label: 'Followers', value: '8.4k'),
            _StatDivider(),
            _StatCell(label: 'Following', value: '310'),
          ],
        ),
        const SizedBox(height: KasySpacing.md),
        // Action buttons
        Row(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            KasyButton(
              label: 'Follow',
              size: KasyButtonSize.small,
              onPressed: () {},
            ),
            const SizedBox(width: KasySpacing.sm),
            KasyButton(
              label: 'Message',
              icon: KasyIcons.message,
              variant: KasyButtonVariant.neutral,
              size: KasyButtonSize.small,
              onPressed: () {},
            ),
          ],
        ),
      ],
    );
  }
}

class _StatCell extends StatelessWidget {
  const _StatCell({required this.label, required this.value});

  final String label;
  final String value;

  @override
  Widget build(BuildContext context) {
    final c = context.colors;
    return Padding(
      padding: const EdgeInsets.symmetric(horizontal: KasySpacing.md),
      child: Column(
        children: [
          Text(
            value,
            style: TextStyle(
              fontSize: 17,
              fontWeight: FontWeight.w700,
              color: c.onSurface,
            ),
          ),
          Text(
            label,
            style: TextStyle(fontSize: 11, color: c.muted),
          ),
        ],
      ),
    );
  }
}

class _StatDivider extends StatelessWidget {
  // ignore: unused_element
  const _StatDivider();

  @override
  Widget build(BuildContext context) {
    return Container(
      width: 1,
      height: 28,
      color: context.colors.outline.withValues(alpha: 0.35),
    );
  }
}

// ── Skeleton profile block ─────────────────────────────────────────────────────

class _SkeletonProfileBlock extends StatelessWidget {
  const _SkeletonProfileBlock();

  @override
  Widget build(BuildContext context) {
    return const Column(
      children: [
        // Avatar circle
        KasySkeleton.circle(size: 70),
        SizedBox(height: KasySpacing.smd),
        // Name
        KasySkeleton(width: 140, height: 18),
        SizedBox(height: KasySpacing.xs),
        // Handle
        KasySkeleton(width: 96, height: 12),
        SizedBox(height: KasySpacing.smd),
        // Bio lines
        KasySkeleton(width: double.infinity, height: 12),
        SizedBox(height: KasySpacing.xs),
        KasySkeleton(width: double.infinity, height: 12),
        SizedBox(height: KasySpacing.xs),
        KasySkeleton(width: 180, height: 12),
        SizedBox(height: KasySpacing.md),
        // Stats row
        Row(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            _SkeletonStatCell(),
            SizedBox(width: KasySpacing.xl),
            _SkeletonStatCell(),
            SizedBox(width: KasySpacing.xl),
            _SkeletonStatCell(),
          ],
        ),
        SizedBox(height: KasySpacing.md),
        // Buttons row
        Row(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            KasySkeleton(
              width: 88,
              height: 34,
              borderRadius: BorderRadius.all(Radius.circular(KasyRadius.sm)),
            ),
            SizedBox(width: KasySpacing.sm),
            KasySkeleton(
              width: 110,
              height: 34,
              borderRadius: BorderRadius.all(Radius.circular(KasyRadius.sm)),
            ),
          ],
        ),
      ],
    );
  }
}

class _SkeletonStatCell extends StatelessWidget {
  const _SkeletonStatCell();

  @override
  Widget build(BuildContext context) {
    return const Column(
      children: [
        KasySkeleton(width: 36, height: 16),
        SizedBox(height: KasySpacing.xs),
        KasySkeleton(width: 52, height: 10),
      ],
    );
  }
}

// ─── Grid skeleton preview ────────────────────────────────────────────────────

const List<String> _kGridImages = [
  'https://images.unsplash.com/photo-1682687220742-aba13b6e50ba?w=400&q=75&fit=crop',
  'https://images.unsplash.com/photo-1469474968028-56623f02e42e?w=400&q=75&fit=crop',
  'https://images.unsplash.com/photo-1447752875215-b2761acb3c5d?w=400&q=75&fit=crop',
  'https://images.unsplash.com/photo-1433086966358-54859d0ed716?w=400&q=75&fit=crop',
];

const List<({String title, String subtitle})> _kGridItems = [
  (title: 'Golden Dunes', subtitle: 'Sahara, Morocco'),
  (title: 'Forest Path', subtitle: 'British Columbia'),
  (title: 'Autumn Maple', subtitle: 'Kyoto, Japan'),
  (title: 'Waterfall', subtitle: 'Plitvice, Croatia'),
];

class _SkeletonGridPreview extends StatefulWidget {
  const _SkeletonGridPreview();

  @override
  State<_SkeletonGridPreview> createState() => _SkeletonGridPreviewState();
}

class _SkeletonGridPreviewState extends State<_SkeletonGridPreview> {
  KasySkeletonAnimation _mode = KasySkeletonAnimation.shimmer;
  bool _loading = true;

  @override
  Widget build(BuildContext context) {
    return Column(
      crossAxisAlignment: CrossAxisAlignment.stretch,
      children: [
        _buildContent(context),
        const SizedBox(height: KasySpacing.lg),
        _SkeletonControls(
          mode: _mode,
          loading: _loading,
          onModeChanged: (m) => setState(() => _mode = m),
          onLoadingChanged: (v) => setState(() => _loading = v),
        ),
      ],
    );
  }

  Widget _buildContent(BuildContext context) {
    return Stack(
      children: [
        AnimatedOpacity(
          opacity: _loading ? 0.0 : 1.0,
          duration: const Duration(milliseconds: 260),
          curve: Curves.easeOut,
          child: _buildRealGrid(context),
        ),
        IgnorePointer(
          ignoring: !_loading,
          child: AnimatedOpacity(
            opacity: _loading ? 1.0 : 0.0,
            duration: const Duration(milliseconds: 200),
            curve: Curves.easeIn,
            child: KasySkeletonGroup(
              animation: _mode,
              child: const _SkeletonGrid(),
            ),
          ),
        ),
      ],
    );
  }

  Widget _buildRealGrid(BuildContext context) {
    final c = context.colors;

    return GridView.count(
      crossAxisCount: 2,
      crossAxisSpacing: KasySpacing.sm,
      mainAxisSpacing: KasySpacing.sm,
      childAspectRatio: 1.05,
      shrinkWrap: true,
      physics: const NeverScrollableScrollPhysics(),
      children: List.generate(_kGridItems.length, (i) {
        final item = _kGridItems[i];
        final url = _kGridImages[i];
        return KasyCard(
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              // Image
              Expanded(
                child: SizedBox(
                  width: double.infinity,
                  child: Image.network(
                    url,
                    fit: BoxFit.cover,
                    loadingBuilder: (context, child, progress) {
                      if (progress == null) return child;
                      return ColoredBox(
                        color: c.surfaceNeutralSoft,
                        child: Center(
                          child: CircularProgressIndicator(
                            color: c.primary,
                            strokeWidth: 2,
                            value: progress.expectedTotalBytes != null
                                ? progress.cumulativeBytesLoaded /
                                    progress.expectedTotalBytes!
                                : null,
                          ),
                        ),
                      );
                    },
                    errorBuilder: (context, error, stackTrace) => ColoredBox(
                      color: c.surfaceNeutralSoft,
                      child: Center(
                        child: Icon(
                          KasyIcons.gallery,
                          size: 28,
                          color: c.muted,
                        ),
                      ),
                    ),
                  ),
                ),
              ),
              // Text
              Padding(
                padding: const EdgeInsets.all(KasySpacing.sm),
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    Text(
                      item.title,
                      style: TextStyle(
                        fontSize: 13,
                        fontWeight: FontWeight.w600,
                        color: c.onSurface,
                      ),
                      maxLines: 1,
                      overflow: TextOverflow.ellipsis,
                    ),
                    const SizedBox(height: 2),
                    Text(
                      item.subtitle,
                      style: TextStyle(fontSize: 11, color: c.muted),
                      maxLines: 1,
                      overflow: TextOverflow.ellipsis,
                    ),
                  ],
                ),
              ),
            ],
          ),
        );
      }),
    );
  }
}

// ── Skeleton grid ──────────────────────────────────────────────────────────────

class _SkeletonGrid extends StatelessWidget {
  const _SkeletonGrid();

  @override
  Widget build(BuildContext context) {
    return GridView.count(
      crossAxisCount: 2,
      crossAxisSpacing: KasySpacing.sm,
      mainAxisSpacing: KasySpacing.sm,
      childAspectRatio: 1.05,
      shrinkWrap: true,
      physics: const NeverScrollableScrollPhysics(),
      children: const [
        _SkeletonGridCell(subtitleWidth: 72),
        _SkeletonGridCell(subtitleWidth: 88),
        _SkeletonGridCell(subtitleWidth: 80),
        _SkeletonGridCell(subtitleWidth: 76),
      ],
    );
  }
}

class _SkeletonGridCell extends StatelessWidget {
  const _SkeletonGridCell({required this.subtitleWidth});

  final double subtitleWidth;

  @override
  Widget build(BuildContext context) {
    return KasyCard(
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          // Image block — fills the card above the text area
          const Expanded(
            child: KasySkeleton(
              width: double.infinity,
              borderRadius: BorderRadius.vertical(
                top: Radius.circular(KasyRadius.xl),
              ),
              height: double.infinity,
            ),
          ),
          // Text area
          Padding(
            padding: const EdgeInsets.all(KasySpacing.sm),
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                const KasySkeleton(width: double.infinity, height: 12),
                const SizedBox(height: 4),
                KasySkeleton(width: subtitleWidth, height: 10),
              ],
            ),
          ),
        ],
      ),
    );
  }
}

// ─────────────────────────────────────────────────────────────────────────────
// SwipeAction — wrap any tile so the user can swipe it to reveal an action
// ─────────────────────────────────────────────────────────────────────────────

Widget _buildSwipeActionDestructive(BuildContext context) =>
    const _SwipeActionPreview(tone: KasySwipeActionTone.destructive);

Widget _buildSwipeActionNeutral(BuildContext context) =>
    const _SwipeActionPreview(
      tone: KasySwipeActionTone.neutral,
      icon: Icons.archive_outlined,
    );

Widget _buildSwipeActionWithConfirm(BuildContext context) =>
    const _SwipeActionPreview(
      tone: KasySwipeActionTone.destructive,
      useConfirm: true,
    );

class _SwipeActionPreview extends StatefulWidget {
  final KasySwipeActionTone tone;
  final IconData? icon;
  final bool useConfirm;

  const _SwipeActionPreview({
    required this.tone,
    this.icon,
    this.useConfirm = false,
  });

  @override
  State<_SwipeActionPreview> createState() => _SwipeActionPreviewState();
}

class _SwipeActionPreviewState extends State<_SwipeActionPreview> {
  late List<_SwipePreviewItem> _items = _initial();

  List<_SwipePreviewItem> _initial() => List.generate(
        4,
        (i) => _SwipePreviewItem(
          id: i,
          title: 'Item ${i + 1}',
          subtitle: 'Swipe left to ${widget.useConfirm ? 'try to ' : ''}remove',
        ),
      );

  void _reset() => setState(() => _items = _initial());

  Future<bool> _confirm() async {
    bool confirmed = false;
    await showKasyConfirmDialog(
      context,
      title: 'Remove item?',
      message: 'This is just a preview — nothing is actually deleted.',
      cancelLabel: 'Cancel',
      confirmLabel: 'Remove',
      destructive: true,
      onConfirm: () => confirmed = true,
    );
    return confirmed;
  }

  @override
  Widget build(BuildContext context) {
    if (_items.isEmpty) {
      return Padding(
        padding: const EdgeInsets.all(KasySpacing.lg),
        child: Column(
          children: [
            Text(
              'All items removed',
              style: context.textTheme.bodyMedium,
              textAlign: TextAlign.center,
            ),
            const SizedBox(height: KasySpacing.sm),
            KasyButton(
              label: 'Reset preview',
              variant: KasyButtonVariant.outline,
              onPressed: _reset,
            ),
          ],
        ),
      );
    }
    return Column(
      crossAxisAlignment: CrossAxisAlignment.stretch,
      children: [
        for (final item in _items)
          widget.useConfirm
              ? KasySwipeAction.withConfirm(
                  key: ValueKey('swipe_confirm_${item.id}'),
                  onDismissed: () =>
                      setState(() => _items.removeWhere((i) => i.id == item.id)),
                  confirm: _confirm,
                  tone: widget.tone,
                  icon: widget.icon ?? KasyIcons.trash,
                  child: _SwipePreviewTile(item: item),
                )
              : KasySwipeAction(
                  key: ValueKey('swipe_${item.id}'),
                  onDismissed: () =>
                      setState(() => _items.removeWhere((i) => i.id == item.id)),
                  tone: widget.tone,
                  icon: widget.icon ?? KasyIcons.trash,
                  child: _SwipePreviewTile(item: item),
                ),
      ],
    );
  }
}

class _SwipePreviewItem {
  final int id;
  final String title;
  final String subtitle;
  const _SwipePreviewItem({
    required this.id,
    required this.title,
    required this.subtitle,
  });
}

class _SwipePreviewTile extends StatelessWidget {
  final _SwipePreviewItem item;
  const _SwipePreviewTile({required this.item});

  @override
  Widget build(BuildContext context) {
    return Container(
      padding: const EdgeInsets.all(KasySpacing.md),
      decoration: BoxDecoration(
        color: context.colors.surface,
        border: Border(
          bottom: BorderSide(color: context.colors.outline, width: 0.5),
        ),
      ),
      child: Row(
        children: [
          Container(
            width: 40,
            height: 40,
            decoration: BoxDecoration(
              color: context.colors.surfaceNeutralSoft,
              borderRadius: BorderRadius.circular(KasyRadius.md),
            ),
            child: Icon(KasyIcons.assistant, color: context.colors.onSurface),
          ),
          const SizedBox(width: KasySpacing.md),
          Expanded(
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                Text(item.title, style: context.textTheme.bodyMedium),
                Text(
                  item.subtitle,
                  style: context.textTheme.bodySmall?.copyWith(
                    color: context.colors.muted,
                  ),
                ),
              ],
            ),
          ),
        ],
      ),
    );
  }
}
