import { Ionicons } from '@expo/vector-icons';
import * as Haptics from 'expo-haptics';
import { useFocusEffect, useRouter } from 'expo-router';
import { useCallback, useEffect, useMemo, useState } from 'react';
import { ActivityIndicator, Alert, Platform, Pressable, ScrollView, StyleSheet, View } from 'react-native';

import { AddClassModal } from '@/components/add-class-modal';
import { useGlobalAddClass } from '@/components/global-add-class';
import {
  AppHeader,
  AppText,
  AttendanceRing,
  BottomSheet,
  Button,
  Card,
  CurrentTimeIndicator,
  EmptyState,
  IconButton,
  InlineBanner,
  RecessCard,
  ScheduleEventCard,
  Screen,
  WeekStrip,
  colors,
  radius,
  size,
  spacing,
  type WeekDay,
} from '@/components/ui';
import {
  addDays,
  currentMinutes,
  dateKey,
  formatCurrentTime,
  formatDayHeading,
  formatHeaderDate,
  formatMonthYear,
  mondayOfWeek,
  timeToMinutes,
} from '@/lib/date';
import { attendanceTone, subjectToneFor } from '@/lib/design';
import { collegeApi, type AttendanceStatus, type Profile, type Session } from '@/lib/api';

type DayMarker = WeekDay['marker'];

type AttendanceSummary = { total: number; attended: number; percentage: number };

const emptySummary: AttendanceSummary = { total: 0, attended: 0, percentage: 0 };
const startOfMonth = (date: Date) => new Date(date.getFullYear(), date.getMonth(), 1);
const daysInMonth = (date: Date) => new Date(date.getFullYear(), date.getMonth() + 1, 0).getDate();

export default function TodayScreen() {
  const router = useRouter();
  const { revision: globalAddRevision } = useGlobalAddClass();
  const [activeDate, setActiveDate] = useState(() => new Date());
  const [calendarMonth, setCalendarMonth] = useState(() => startOfMonth(new Date()));
  const [classes, setClasses] = useState<Session[]>([]);
  const [profile, setProfile] = useState<Profile | null>(null);
  const [summary, setSummary] = useState<AttendanceSummary>(emptySummary);
  const [weekendSchedule, setWeekendSchedule] = useState(false);
  const [weekMarkers, setWeekMarkers] = useState<Record<string, DayMarker>>({});
  const [monthMarkers, setMonthMarkers] = useState<Record<string, DayMarker>>({});
  const [loading, setLoading] = useState(true);
  const [loadError, setLoadError] = useState('');
  const [refresh, setRefresh] = useState(0);
  const [calendarExpanded, setCalendarExpanded] = useState(false);
  const [addClassOpen, setAddClassOpen] = useState(false);
  const [selectedClass, setSelectedClass] = useState<Session | null>(null);

  const today = new Date();
  const todayKey = dateKey(today);
  const selectedDateKey = dateKey(activeDate);
  const weekStart = useMemo(() => mondayOfWeek(activeDate), [activeDate]);
  const weekDates = useMemo(() => Array.from({ length: 7 }, (_, index) => addDays(weekStart, index)), [weekStart]);

  useFocusEffect(useCallback(() => {
    let active = true;
    collegeApi.profile().then((result) => {
      if (!active) return;
      setProfile(result);
      const weekendsEnabled = Boolean(result.weekendSchedule);
      setWeekendSchedule(weekendsEnabled);
      if (!weekendsEnabled) {
        setActiveDate((current) => {
          if (current.getDay() === 6) return addDays(current, 2);
          if (current.getDay() === 0) return addDays(current, 1);
          return current;
        });
      }
    }).catch(() => undefined);
    return () => { active = false; };
  }, []));

  const loadSchedule = useCallback(() => {
    setLoading(true);
    setLoadError('');
    collegeApi.schedule(selectedDateKey)
      .then(({ sessions }) => setClasses(sessions))
      .catch((error: Error) => { setClasses([]); setLoadError(error.message); })
      .finally(() => setLoading(false));
  }, [selectedDateKey]);

  useEffect(() => { loadSchedule(); }, [loadSchedule, refresh]);

  useEffect(() => {
    if (globalAddRevision > 0) setRefresh((current) => current + 1);
  }, [globalAddRevision]);

  useEffect(() => {
    collegeApi.attendanceSummary().then(({ subjects }) => {
      const total = subjects.reduce((value, subject) => value + subject.total, 0);
      const attended = subjects.reduce((value, subject) => value + subject.attended, 0);
      setSummary({ total, attended, percentage: total ? Math.round(attended / total * 100) : 0 });
    }).catch(() => setSummary(emptySummary));
  }, [refresh]);

  useEffect(() => {
    Promise.all(weekDates.map((date) => collegeApi.schedule(dateKey(date)).then(({ sessions }) => ({ date, sessions })).catch(() => ({ date, sessions: [] as Session[] }))))
      .then((results) => {
        const markers: Record<string, DayMarker> = {};
        results.forEach(({ date, sessions }) => {
          const key = dateKey(date);
          if (key > todayKey) return;
          const held = sessions.filter((session) => session.status !== 'cancelled');
          if (!held.length) return;
          if (held.every((session) => session.status === 'attended')) markers[key] = 'success';
          else if (held.some((session) => session.status === 'absent')) markers[key] = 'danger';
          else if (held.some((session) => session.status === 'pending')) markers[key] = 'warning';
          else markers[key] = 'neutral';
        });
        setWeekMarkers(markers);
      });
  }, [refresh, todayKey, weekDates]);

  const visibleDays: WeekDay[] = weekDates
    .filter((date) => weekendSchedule || (date.getDay() !== 0 && date.getDay() !== 6))
    .map((date) => ({ date, marker: weekMarkers[dateKey(date)] ?? 'none' }));

  const calendarMonthKey = `${calendarMonth.getFullYear()}-${String(calendarMonth.getMonth() + 1).padStart(2, '0')}`;
  useEffect(() => {
    collegeApi.attendanceMarkers(calendarMonthKey)
      .then(({ markers }) => setMonthMarkers(markers))
      .catch(() => setMonthMarkers({}));
  }, [calendarMonthKey, refresh]);

  const updateStatus = (session: Session, status: AttendanceStatus) => {
    const previous = classes;
    setClasses((items) => items.map((item) => item.id === session.id ? { ...item, status } : item));
    setSummary((current) => {
      const wasHeld = session.status === 'attended' || session.status === 'absent';
      const isHeld = status === 'attended' || status === 'absent';
      const total = current.total + (isHeld ? 1 : 0) - (wasHeld ? 1 : 0);
      const attended = current.attended + (status === 'attended' ? 1 : 0) - (session.status === 'attended' ? 1 : 0);
      return { total, attended, percentage: total ? Math.round((attended / total) * 100) : 0 };
    });
    collegeApi.markAttendance(session.id, status)
      .then(() => {
        if (Platform.OS !== 'web') void Haptics.notificationAsync(Haptics.NotificationFeedbackType.Success);
      })
      .catch((error: Error) => {
        setClasses(previous);
        setSummary((current) => {
          const wasHeld = session.status === 'attended' || session.status === 'absent';
          const isHeld = status === 'attended' || status === 'absent';
          const total = current.total + (wasHeld ? 1 : 0) - (isHeld ? 1 : 0);
          const attended = current.attended + (session.status === 'attended' ? 1 : 0) - (status === 'attended' ? 1 : 0);
          return { total, attended, percentage: total ? Math.round((attended / total) * 100) : 0 };
        });
        Alert.alert('Couldn’t save attendance', error.message);
      });
  };

  const removeClass = (session: Session) => {
    Alert.alert('Remove this class?', 'This removes only this occurrence. Your recurring timetable will not change.', [
      { text: 'Keep class', style: 'cancel' },
      { text: 'Remove', style: 'destructive', onPress: () => {
        setSelectedClass(null);
        setClasses((items) => items.filter((item) => item.id !== session.id));
        collegeApi.removeClass(session.id).then(() => setRefresh((value) => value + 1)).catch((error: Error) => {
          Alert.alert('Couldn’t remove class', error.message);
          setRefresh((value) => value + 1);
        });
      } },
    ]);
  };

  const isToday = selectedDateKey === todayKey;
  const insightTone = attendanceTone(summary.percentage, summary.total);
  const now = currentMinutes();
  const recessEnabled = Boolean(profile && profile.recessEnabled && timeToMinutes(profile.recessStart) >= 0 && timeToMinutes(profile.recessStart) < timeToMinutes(profile.recessEnd));
  const timelineItems = [
    ...classes.map((item) => ({ type: 'class' as const, start: item.time, end: item.endTime, item })),
    ...(recessEnabled ? [{ type: 'recess' as const, start: profile!.recessStart, end: profile!.recessEnd }] : []),
  ].sort((left, right) => left.start.localeCompare(right.start) || (left.type === 'recess' ? -1 : 1));
  const activeTimelineIndex = isToday ? timelineItems.findIndex((item) => timeToMinutes(item.start) <= now && now < timeToMinutes(item.end)) : -1;
  const insertionIndex = isToday ? (activeTimelineIndex >= 0 ? activeTimelineIndex : timelineItems.findIndex((item) => timeToMinutes(item.start) > now)) : -1;
  const currentTimeLabel = formatCurrentTime();
  const pendingCount = classes.filter((item) => item.status === 'pending').length;
  const metricTone = summary.total ? (insightTone === 'neutral' ? 'brand' : insightTone) : 'brand';
  const collapseCalendar = () => {
    if (calendarExpanded) setCalendarExpanded(false);
  };

  return <Screen scroll={false} contentContainerStyle={styles.content}>
    <View style={styles.stickyHeader}>
    <View style={styles.headerRow} onTouchStart={collapseCalendar}>
      <AppHeader
        title={formatHeaderDate(activeDate)}
        style={styles.headerTitle}
      />
      {profile?.name ? (
        <Pressable
          accessibilityRole="button"
          accessibilityLabel="Open account profile"
          onPress={() => router.push('/account' as never)}
          style={({ pressed }) => [styles.avatar, pressed && styles.avatarPressed]}>
          <AppText variant="label" color={colors.brand.cobalt}>{profile.initials || '?'}</AppText>
        </Pressable>
      ) : null}
    </View>

    <View style={styles.attendanceOverview} onTouchStart={collapseCalendar}>
      <View style={styles.overviewPrimary}>
        <AttendanceRing
          percentage={summary.percentage}
          tone={metricTone}
          size={76}
          strokeWidth={8}
          label=""
          accessibilityLabel={summary.total ? `Overall attendance ${summary.percentage} percent` : 'No attendance data yet'}
        />
        <View style={styles.overviewCopy}>
          <AppText variant="title">{summary.total ? `${summary.percentage}% overall` : 'No attendance yet'}</AppText>
          <AppText variant="bodySmall" color={colors.neutral.textSecondary} style={styles.overviewMessage}>
            {summary.total ? `${summary.attended} of ${summary.total} classes attended` : 'Mark a class to begin tracking.'}
          </AppText>
        </View>
      </View>
      <View style={styles.overviewTarget}>
        <AppText variant="caption" color={colors.neutral.textMuted}>Target</AppText>
        <AppText variant="title" color={colors.brand.cobalt} style={styles.overviewTargetValue}>75%</AppText>
      </View>
    </View>

    <View style={styles.pickerContainer} onTouchStart={(event) => event.stopPropagation()}>
      {calendarExpanded ? (
        <InlineCalendarWidget
          month={calendarMonth}
          selectedDateKey={selectedDateKey}
          todayKey={todayKey}
          markers={monthMarkers}
          allowWeekends={weekendSchedule}
          onMonthChange={setCalendarMonth}
          onSelect={(date) => {
            setActiveDate(date);
            setCalendarExpanded(false);
          }}
        />
      ) : (
        <WeekStrip days={visibleDays} selectedDateKey={selectedDateKey} todayDateKey={todayKey} onSelect={setActiveDate} style={styles.weekStrip} />
      )}
      <Pressable
        accessibilityRole="button"
        accessibilityLabel={calendarExpanded ? 'Collapse calendar' : 'Expand calendar'}
        onPress={() => {
          if (!calendarExpanded) {
            setCalendarMonth(startOfMonth(activeDate));
          }
          setCalendarExpanded((v) => !v);
        }}
        style={({ pressed }) => [styles.extendBar, pressed && styles.extendBarPressed]}>
        <View style={styles.extendHandle} />
      </Pressable>
    </View>

    <View style={styles.sectionHeader} onTouchStart={collapseCalendar}>
      <View style={styles.sectionCopy}>
        <AppText variant="heading2">Schedule</AppText>
        <AppText variant="bodySmall" color={colors.neutral.textMuted} style={styles.sectionSubtitle}>
          {classes.length ? `${classes.length} ${classes.length === 1 ? 'class' : 'classes'}${pendingCount ? ` · ${pendingCount} to mark` : ''}` : 'Your agenda for this date'}
        </AppText>
      </View>
    </View>

    </View>

    <ScrollView style={styles.classList} contentContainerStyle={styles.classListContent} showsVerticalScrollIndicator={false} keyboardShouldPersistTaps="handled" onTouchStart={collapseCalendar}>
    {loadError ? <InlineBanner title="Couldn’t load this day" message={loadError} tone="danger" action={<Button label="Retry" size="compact" variant="ghost" fullWidth={false} onPress={loadSchedule} />} /> : null}
    {loading ? <Card tone="skySoft" style={styles.loading}><ActivityIndicator color={colors.brand.cobalt} /><AppText variant="bodySmall" color={colors.neutral.textSecondary}>Loading your classes…</AppText></Card> : null}
    {!loading && !loadError && classes.length === 0 && !recessEnabled ? <EmptyState icon="calendar-clear-outline" title="No classes scheduled" message="Enjoy the break, or add a one-off class for this date." action={<Button label="Add a class" variant="secondary" onPress={() => setAddClassOpen(true)} leading={<Ionicons name="add" size={18} color={colors.brand.cobalt} />} />} /> : null}

    {!loading && !loadError && timelineItems.length > 0 ? <View style={styles.timeline}>
      {timelineItems.map((entry, index) => {
        const isNow = index === activeTimelineIndex;
        const key = entry.type === 'class' ? `class-${entry.item.id}` : `recess-${entry.start}`;
        return <View key={key}>
          {index === insertionIndex ? <CurrentTimeIndicator time={currentTimeLabel} /> : null}
          <View style={styles.classRow}>
            <View style={styles.timeRail}>
              <AppText variant="label" style={styles.timeText}>{entry.start}</AppText>
              {index < timelineItems.length - 1 ? <View style={styles.railLine} /> : null}
            </View>
            {entry.type === 'recess' ? <RecessCard timeRange={`${entry.start}–${entry.end}`} isNow={isNow} style={styles.event} /> : <ScheduleEventCard
              title={entry.item.title}
              kind={entry.item.code}
              classType={entry.item.classType}
              timeRange={`${entry.start}–${entry.end}`}
              room={entry.item.room}
              subjectTone={subjectToneFor(entry.item.subjectId || entry.item.code, entry.item.color)}
              state={entry.item.status}
              isNow={isNow}
              style={styles.event}
              topAction={<IconButton icon="ellipsis-horizontal" label={`Options for ${entry.item.title}`} tone="ghost" onPress={() => setSelectedClass(entry.item)} />}
              footer={entry.item.status !== 'cancelled' ? <AttendanceActions tone={subjectToneFor(entry.item.subjectId || entry.item.code, entry.item.color)} status={entry.item.status} onAttended={() => updateStatus(entry.item, 'attended')} onAbsent={() => updateStatus(entry.item, 'absent')} /> : null}
            />}
          </View>
        </View>;
      })}
      {isToday && insertionIndex === -1 && activeTimelineIndex === -1 ? <CurrentTimeIndicator time={currentTimeLabel} /> : null}
    </View> : null}
    </ScrollView>

    <AddClassModal visible={addClassOpen} date={selectedDateKey} onClose={() => setAddClassOpen(false)} onAdded={() => setRefresh((value) => value + 1)} />

    <BottomSheet visible={Boolean(selectedClass)} title="Class options" onClose={() => setSelectedClass(null)}>
      {selectedClass ? <>
        <Card tone="skySoft" style={styles.selectedClassSummary}>
          <AppText variant="title">{selectedClass.title}</AppText>
          <AppText variant="bodySmall" color={colors.neutral.textSecondary} style={styles.sectionSubtitle}>{selectedClass.code} · {selectedClass.time}–{selectedClass.endTime} · {selectedClass.room}</AppText>
        </Card>
        <View style={styles.sheetButtons}>
          <Button label="View subject" variant="secondary" disabled={!selectedClass.subjectId} onPress={() => { const id = selectedClass.subjectId; setSelectedClass(null); if (id) router.push(`/subjects/${id}` as never); }} leading={<Ionicons name="book-outline" size={18} color={colors.brand.cobalt} />} />
          {selectedClass.status !== 'cancelled' ? <Button label="Cancel class" variant="ghost" onPress={() => { updateStatus(selectedClass, 'cancelled'); setSelectedClass(null); }} leading={<Ionicons name="remove-circle-outline" size={18} color={colors.semantic.danger.text} />} /> : null}
          <Button label="Remove from this day" variant="ghost" onPress={() => removeClass(selectedClass)} leading={<Ionicons name="trash-outline" size={18} color={colors.semantic.danger.text} />} />
        </View>
      </> : null}
    </BottomSheet>
  </Screen>;
}

function AttendanceActions({ tone, status, onAttended, onAbsent }: { tone: keyof typeof colors.subject; status?: AttendanceStatus; onAttended: () => void; onAbsent: () => void }) {
  const palette = colors.subject[tone];
  const isAttended = status === 'attended';
  const isAbsent = status === 'absent';
  return <View style={styles.attendanceActions}>
    <Pressable
      accessibilityRole="button"
      accessibilityLabel="Mark attended"
      onPress={onAttended}
      style={({ pressed }) => [
        styles.attendanceButton,
        { borderColor: isAttended ? colors.semantic.success.solid : palette.accent },
        isAttended && { backgroundColor: colors.semantic.success.solid },
        pressed && styles.actionPressed,
      ]}>
      <Ionicons name="checkmark" size={18} color={isAttended ? colors.neutral.surface : palette.accent} />
    </Pressable>
    <Pressable
      accessibilityRole="button"
      accessibilityLabel="Mark absent"
      onPress={onAbsent}
      style={({ pressed }) => [
        styles.attendanceButton,
        { borderColor: isAbsent ? colors.semantic.danger.solid : palette.accent },
        isAbsent && { backgroundColor: colors.semantic.danger.solid },
        pressed && styles.actionPressed,
      ]}>
      <Ionicons name="close" size={18} color={isAbsent ? colors.neutral.surface : palette.accent} />
    </Pressable>
  </View>;
}

const markerColorMap = {
  none: 'transparent',
  success: colors.semantic.success.solid,
  warning: colors.semantic.warning.solid,
  danger: colors.semantic.danger.solid,
  neutral: colors.neutral.textMuted,
} as const;

function InlineCalendarWidget({
  month,
  selectedDateKey,
  todayKey,
  markers = {},
  allowWeekends = false,
  onMonthChange,
  onSelect,
}: {
  month: Date;
  selectedDateKey: string;
  todayKey: string;
  markers?: Record<string, DayMarker>;
  allowWeekends?: boolean;
  onMonthChange: (date: Date) => void;
  onSelect: (date: Date) => void;
}) {
  const offset = (month.getDay() + 6) % 7;
  const dates = Array.from({ length: offset + daysInMonth(month) }, (_, index) => (index < offset ? null : index - offset + 1));
  const weekdayLabels = ['mon', 'tue', 'wed', 'thu', 'fri', 'sat', 'sun'];

  return (
    <View style={styles.calendarWidget}>
      <View style={styles.monthNavigation}>
        <IconButton icon="chevron-back" label="Previous month" tone="ghost" onPress={() => onMonthChange(new Date(month.getFullYear(), month.getMonth() - 1, 1))} />
        <AppText variant="title">{formatMonthYear(month)}</AppText>
        <IconButton icon="chevron-forward" label="Next month" tone="ghost" onPress={() => onMonthChange(new Date(month.getFullYear(), month.getMonth() + 1, 1))} />
      </View>
      <View style={styles.calendarWeekdays}>
        {weekdayLabels.map((label, index) => {
          const isWeekendCol = index >= 5;
          const disabledCol = isWeekendCol && !allowWeekends;
          return (
            <AppText
              key={`${label}-${index}`}
              variant="caption"
              color={disabledCol ? colors.neutral.textDisabled : colors.neutral.textMuted}
              style={[styles.calendarWeekday, disabledCol && styles.calendarDisabledText]}>
              {label}
            </AppText>
          );
        })}
      </View>
      <View style={styles.calendarGrid}>
        {dates.map((day, index) => {
          if (!day) return <View key={`empty-${index}`} style={styles.calendarCell} />;
          const date = new Date(month.getFullYear(), month.getMonth(), day);
          const key = dateKey(date);
          const dayOfWeek = date.getDay();
          const isWeekend = dayOfWeek === 0 || dayOfWeek === 6;
          const isDisabled = isWeekend && !allowWeekends;
          const selected = key === selectedDateKey;
          const isToday = key === todayKey;
          const marker = markers[key] ?? 'none';

          return (
            <Pressable
              key={key}
              accessibilityRole="button"
              accessibilityLabel={formatDayHeading(date)}
              accessibilityState={{ selected, disabled: isDisabled }}
              disabled={isDisabled}
              onPress={() => onSelect(date)}
              style={({ pressed }) => [
                styles.calendarCell,
                selected && styles.calendarSelected,
                isToday && !selected && styles.calendarToday,
                isDisabled && styles.calendarCellDisabled,
                pressed && !isDisabled && styles.actionPressed,
              ]}>
              <AppText
                variant="label"
                color={selected ? colors.brand.ink : isDisabled ? colors.neutral.textDisabled : colors.neutral.textPrimary}
                style={[styles.timeText, isDisabled && styles.calendarDisabledText]}>
                {day}
              </AppText>
              <View style={styles.indicatorRow}>
                <View
                  style={[
                    styles.dot,
                    isToday && !selected && styles.todayDot,
                    marker !== 'none' && !isDisabled && { backgroundColor: markerColorMap[marker] },
                  ]}
                />
              </View>
            </Pressable>
          );
        })}
      </View>
    </View>
  );
}

const styles = StyleSheet.create({
  // Bottom padding belongs to the scrollable class content, not this fixed shell.
  content: { paddingTop: spacing[1], paddingBottom: 0 },

  stickyHeader: { flexShrink: 0, position: 'relative', zIndex: 20, elevation: 20 },
  headerRow: { flexDirection: 'row', alignItems: 'flex-start', justifyContent: 'space-between', gap: spacing[2], marginBottom: spacing[3] },
  headerTitle: { flex: 1, minHeight: 0 },
  headerActions: { flexDirection: 'row', alignItems: 'center', gap: spacing[2], paddingTop: spacing[1] },
  avatar: { width: 40, height: 40, borderRadius: radius.control, borderCurve: 'continuous', backgroundColor: colors.brand.cobaltSoft, alignItems: 'center', justifyContent: 'center' },
  avatarPressed: { opacity: 0.78 },
  attendanceOverview: {
    marginTop: spacing[3],
    marginBottom: spacing[3],
    minHeight: 96,
    flexDirection: 'row',
    alignItems: 'center',
    justifyContent: 'space-between',
    gap: spacing[4],
    paddingHorizontal: spacing[4],
    paddingVertical: spacing[3],
    borderRadius: radius.feature,
    borderCurve: 'continuous',
    backgroundColor: colors.brand.skySoft,
    borderWidth: 1,
    borderColor: '#DCEEF8',
  },
  overviewPrimary: { flex: 1, flexDirection: 'row', alignItems: 'center', gap: spacing[3] },
  overviewCopy: { flex: 1 },
  overviewMessage: { marginTop: spacing[1] },
  overviewTarget: { alignItems: 'flex-end', gap: 2, paddingRight: spacing[1] },
  overviewTargetValue: { fontVariant: ['tabular-nums'] },
  pickerContainer: {
    marginTop: spacing[1],
    position: 'relative',
    zIndex: 30,
    elevation: 30,
    borderRadius: radius.feature,
    borderCurve: 'continuous',
    backgroundColor: colors.brand.skySoft,
    overflow: 'hidden',
    borderWidth: 1,
    borderColor: '#E2F0FA',
  },
  weekStrip: {
    width: '100%',
    borderRadius: 0,
    backgroundColor: 'transparent',
  },
  calendarWidget: {
    backgroundColor: 'transparent',
    paddingHorizontal: spacing[2],
    paddingTop: spacing[3],
    paddingBottom: spacing[1],
  },
  extendBar: {
    height: 16,
    alignItems: 'center',
    justifyContent: 'center',
    backgroundColor: 'transparent',
    borderTopWidth: 1,
    borderTopColor: '#E2EEF8',
  },
  extendHandle: {
    width: 36,
    height: 3.5,
    borderRadius: 2,
    backgroundColor: colors.neutral.textDisabled,
    opacity: 0.7,
  },
  extendBarPressed: { opacity: 0.6 },
  calendarCellDisabled: { opacity: 0.28 },
  calendarDisabledText: { textDecorationLine: 'none' },
  indicatorRow: { height: 5, marginTop: 1, justifyContent: 'center', alignItems: 'center' },
  dot: { width: 4, height: 4, borderRadius: 2, backgroundColor: 'transparent' },
  todayDot: { width: 4.5, height: 4.5, borderRadius: 2.5, backgroundColor: colors.brand.cobalt },
  sectionHeader: { marginTop: spacing[8], marginBottom: spacing[4], flexDirection: 'row', alignItems: 'center', justifyContent: 'space-between', gap: spacing[4] },
  sectionCopy: { flex: 1 },
  sectionSubtitle: { marginTop: spacing[1] },
  loading: { minHeight: 112, flexDirection: 'row', alignItems: 'center', justifyContent: 'center', gap: spacing[3] },
  timeline: { gap: spacing[2] },
  classRow: { flexDirection: 'row', alignItems: 'stretch' },
  timeRail: { width: 50, alignItems: 'flex-start', paddingTop: spacing[4], position: 'relative' },
  timeText: { fontVariant: ['tabular-nums'], fontSize: 13, lineHeight: 17, fontWeight: '700', color: colors.neutral.textSecondary },
  railLine: { position: 'absolute', top: 38, bottom: -10, left: 4, width: 1, backgroundColor: colors.neutral.divider },
  classList: { flex: 1, minHeight: 0 },
  classListContent: { paddingTop: spacing[4], paddingBottom: size.tabBar + spacing[6] },
  event: { flex: 1, marginBottom: spacing[2] },
  attendanceActions: { flexDirection: 'row', alignItems: 'center', gap: spacing[2] },
  attendanceButton: { width: 40, height: 40, alignItems: 'center', justifyContent: 'center', borderRadius: radius.pill, borderWidth: 1, backgroundColor: 'rgba(255, 255, 255, 0.62)' },
  actionPressed: { opacity: 0.72 },
  sheetButtons: { gap: spacing[2], marginTop: spacing[5] },
  selectedClassSummary: { marginTop: spacing[2] },
  monthNavigation: { flexDirection: 'row', alignItems: 'center', justifyContent: 'space-between', marginBottom: spacing[5] },
  calendarWeekdays: { flexDirection: 'row', marginBottom: spacing[2] },
  calendarWeekday: { width: '14.2857%', textAlign: 'center' },
  calendarGrid: { flexDirection: 'row', flexWrap: 'wrap' },
  calendarCell: { width: '14.2857%', aspectRatio: 1, alignItems: 'center', justifyContent: 'center', borderRadius: radius.control, borderCurve: 'continuous' },
  calendarSelected: { backgroundColor: colors.brand.coral },
  calendarToday: { borderWidth: 2, borderColor: colors.brand.cobalt },
  calendarButton: { marginTop: spacing[5] },
});
