<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Premières</title>
    <link>https://premieres.stephanejacquet.fr/</link>
    <description>Recent content on Premières</description>
    <generator>Hugo -- gohugo.io</generator>
    <language>en</language>
    <copyright>Copyright © 2026 Stéphane Jacquet.</copyright>
    <lastBuildDate>Mon, 01 Jan 0001 00:00:00 +0000</lastBuildDate><atom:link href="https://premieres.stephanejacquet.fr/index.xml" rel="self" type="application/rss+xml" />
    
    <item>
      <title>Comparatives and Superlatives</title>
      <link>https://premieres.stephanejacquet.fr/chapters/robinson/adjectives/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      
      <guid>https://premieres.stephanejacquet.fr/chapters/robinson/adjectives/</guid>
      <description>&lt;h1 class=&#34;relative group&#34;&gt;🎯 Comparatives and superlatives&#xA;    &lt;div id=&#34;-comparatives-and-superlatives&#34; class=&#34;anchor&#34;&gt;&lt;/div&gt;&#xA;    &#xA;    &lt;span&#xA;        class=&#34;absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none&#34;&gt;&#xA;        &lt;a class=&#34;text-primary-300 dark:text-neutral-700 !no-underline&#34; href=&#34;#-comparatives-and-superlatives&#34; aria-label=&#34;Anchor&#34;&gt;#&lt;/a&gt;&#xA;    &lt;/span&gt;&#xA;    &#xA;&lt;/h1&gt;&#xA;&lt;hr&gt;&#xA;&#xA;&lt;h2 class=&#34;relative group&#34;&gt;📊 Quick Reference Chart&#xA;    &lt;div id=&#34;-quick-reference-chart&#34; class=&#34;anchor&#34;&gt;&lt;/div&gt;&#xA;    &#xA;    &lt;span&#xA;        class=&#34;absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none&#34;&gt;&#xA;        &lt;a class=&#34;text-primary-300 dark:text-neutral-700 !no-underline&#34; href=&#34;#-quick-reference-chart&#34; aria-label=&#34;Anchor&#34;&gt;#&lt;/a&gt;&#xA;    &lt;/span&gt;&#xA;    &#xA;&lt;/h2&gt;&#xA;&#xA;&lt;h3 class=&#34;relative group&#34;&gt;One-Syllable Adjectives&#xA;    &lt;div id=&#34;one-syllable-adjectives&#34; class=&#34;anchor&#34;&gt;&lt;/div&gt;&#xA;    &#xA;    &lt;span&#xA;        class=&#34;absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none&#34;&gt;&#xA;        &lt;a class=&#34;text-primary-300 dark:text-neutral-700 !no-underline&#34; href=&#34;#one-syllable-adjectives&#34; aria-label=&#34;Anchor&#34;&gt;#&lt;/a&gt;&#xA;    &lt;/span&gt;&#xA;    &#xA;&lt;/h3&gt;&#xA;&lt;table&gt;&#xA;  &lt;thead&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;th&gt;Adjective&lt;/th&gt;&#xA;          &lt;th&gt;Comparative&lt;/th&gt;&#xA;          &lt;th&gt;Superlative&lt;/th&gt;&#xA;      &lt;/tr&gt;&#xA;  &lt;/thead&gt;&#xA;  &lt;tbody&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;tall&lt;/td&gt;&#xA;          &lt;td&gt;tall&lt;strong&gt;er&lt;/strong&gt;&lt;/td&gt;&#xA;          &lt;td&gt;the tall&lt;strong&gt;est&lt;/strong&gt;&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;fast&lt;/td&gt;&#xA;          &lt;td&gt;fast&lt;strong&gt;er&lt;/strong&gt;&lt;/td&gt;&#xA;          &lt;td&gt;the fast&lt;strong&gt;est&lt;/strong&gt;&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;hot&lt;/td&gt;&#xA;          &lt;td&gt;hott&lt;strong&gt;er&lt;/strong&gt;&lt;/td&gt;&#xA;          &lt;td&gt;the hott&lt;strong&gt;est&lt;/strong&gt;&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;big&lt;/td&gt;&#xA;          &lt;td&gt;bigg&lt;strong&gt;er&lt;/strong&gt;&lt;/td&gt;&#xA;          &lt;td&gt;the bigg&lt;strong&gt;est&lt;/strong&gt;&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;  &lt;/tbody&gt;&#xA;&lt;/table&gt;&#xA;&#xA;&lt;h3 class=&#34;relative group&#34;&gt;Two or More Syllables&#xA;    &lt;div id=&#34;two-or-more-syllables&#34; class=&#34;anchor&#34;&gt;&lt;/div&gt;&#xA;    &#xA;    &lt;span&#xA;        class=&#34;absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none&#34;&gt;&#xA;        &lt;a class=&#34;text-primary-300 dark:text-neutral-700 !no-underline&#34; href=&#34;#two-or-more-syllables&#34; aria-label=&#34;Anchor&#34;&gt;#&lt;/a&gt;&#xA;    &lt;/span&gt;&#xA;    &#xA;&lt;/h3&gt;&#xA;&lt;table&gt;&#xA;  &lt;thead&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;th&gt;Adjective&lt;/th&gt;&#xA;          &lt;th&gt;Comparative&lt;/th&gt;&#xA;          &lt;th&gt;Superlative&lt;/th&gt;&#xA;      &lt;/tr&gt;&#xA;  &lt;/thead&gt;&#xA;  &lt;tbody&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;interesting&lt;/td&gt;&#xA;          &lt;td&gt;&lt;strong&gt;more&lt;/strong&gt; interesting&lt;/td&gt;&#xA;          &lt;td&gt;the &lt;strong&gt;most&lt;/strong&gt; interesting&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;beautiful&lt;/td&gt;&#xA;          &lt;td&gt;&lt;strong&gt;more&lt;/strong&gt; beautiful&lt;/td&gt;&#xA;          &lt;td&gt;the &lt;strong&gt;most&lt;/strong&gt; beautiful&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;expensive&lt;/td&gt;&#xA;          &lt;td&gt;&lt;strong&gt;more&lt;/strong&gt; expensive&lt;/td&gt;&#xA;          &lt;td&gt;the &lt;strong&gt;most&lt;/strong&gt; expensive&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;intelligent&lt;/td&gt;&#xA;          &lt;td&gt;&lt;strong&gt;more&lt;/strong&gt; intelligent&lt;/td&gt;&#xA;          &lt;td&gt;the &lt;strong&gt;most&lt;/strong&gt; intelligent&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;  &lt;/tbody&gt;&#xA;&lt;/table&gt;&#xA;&lt;p&gt;&lt;strong&gt;👉 Rule of thumb&lt;/strong&gt;: If it sounds natural with &lt;em&gt;-er/-est&lt;/em&gt;, use that. Otherwise, use &lt;em&gt;more/most&lt;/em&gt;.&lt;/p&gt;</description>
      
    </item>
    
    <item>
      <title>Adjective order</title>
      <link>https://premieres.stephanejacquet.fr/chapters/women_detectives/adjectives/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      
      <guid>https://premieres.stephanejacquet.fr/chapters/women_detectives/adjectives/</guid>
      <description>&lt;h1 class=&#34;relative group&#34;&gt;🎯 Adjectives&#xA;    &lt;div id=&#34;-adjectives&#34; class=&#34;anchor&#34;&gt;&lt;/div&gt;&#xA;    &#xA;    &lt;span&#xA;        class=&#34;absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none&#34;&gt;&#xA;        &lt;a class=&#34;text-primary-300 dark:text-neutral-700 !no-underline&#34; href=&#34;#-adjectives&#34; aria-label=&#34;Anchor&#34;&gt;#&lt;/a&gt;&#xA;    &lt;/span&gt;&#xA;    &#xA;&lt;/h1&gt;&#xA;&lt;hr&gt;&#xA;&#xA;&lt;h2 class=&#34;relative group&#34;&gt;🧱 1. What is an Adjective?&#xA;    &lt;div id=&#34;-1-what-is-an-adjective&#34; class=&#34;anchor&#34;&gt;&lt;/div&gt;&#xA;    &#xA;    &lt;span&#xA;        class=&#34;absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none&#34;&gt;&#xA;        &lt;a class=&#34;text-primary-300 dark:text-neutral-700 !no-underline&#34; href=&#34;#-1-what-is-an-adjective&#34; aria-label=&#34;Anchor&#34;&gt;#&lt;/a&gt;&#xA;    &lt;/span&gt;&#xA;    &#xA;&lt;/h2&gt;&#xA;&lt;p&gt;An &lt;strong&gt;adjective&lt;/strong&gt; is a word that describes a &lt;strong&gt;noun&lt;/strong&gt; or a &lt;strong&gt;pronoun&lt;/strong&gt;.&lt;br&gt;&#xA;It gives information about &lt;em&gt;what something is like&lt;/em&gt;.&lt;br&gt;&#xA;In linguistic terms, an adjective &lt;em&gt;modifies&lt;/em&gt; a noun.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Examples&lt;/strong&gt;:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;A &lt;strong&gt;beautiful&lt;/strong&gt; painting&lt;/li&gt;&#xA;&lt;li&gt;An &lt;strong&gt;ugly&lt;/strong&gt; one&lt;/li&gt;&#xA;&lt;li&gt;The &lt;strong&gt;old&lt;/strong&gt; house&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;hr&gt;&#xA;&#xA;&lt;h2 class=&#34;relative group&#34;&gt;🧭 2. Where Do Adjectives Go?&#xA;    &lt;div id=&#34;-2-where-do-adjectives-go&#34; class=&#34;anchor&#34;&gt;&lt;/div&gt;&#xA;    &#xA;    &lt;span&#xA;        class=&#34;absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none&#34;&gt;&#xA;        &lt;a class=&#34;text-primary-300 dark:text-neutral-700 !no-underline&#34; href=&#34;#-2-where-do-adjectives-go&#34; aria-label=&#34;Anchor&#34;&gt;#&lt;/a&gt;&#xA;    &lt;/span&gt;&#xA;    &#xA;&lt;/h2&gt;&#xA;&lt;p&gt;Adjectives usually come:&lt;/p&gt;</description>
      
    </item>
    
    <item>
      <title>Lexicon</title>
      <link>https://premieres.stephanejacquet.fr/chapters/aborigines/lexicon/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      
      <guid>https://premieres.stephanejacquet.fr/chapters/aborigines/lexicon/</guid>
      <description>&lt;style&gt;&#xA;    .lexicon-list {&#xA;      margin: 1.5rem 0;&#xA;      padding: 0;&#xA;    }&#xA;    .lexicon-list dt {&#xA;      margin: 0;&#xA;      padding: 0;&#xA;      font-weight: 600;&#xA;      font-size: 1.05rem;&#xA;    }&#xA;    .lexicon-list dd {&#xA;      margin: 0.15rem 0 1rem 0;&#xA;      padding: 0;&#xA;      color: inherit;&#xA;      opacity: 0.85;&#xA;    }&#xA;    .lexicon-list dd p {&#xA;      margin: 0;&#xA;    }&#xA;  &lt;/style&gt;&#xA;  &lt;h2&gt;📖 Aboriginal Dreams - Australian Lands &amp;mdash; Vocabulary&lt;/h2&gt;&lt;p&gt;&lt;em&gt;No vocabulary for this unit yet.&lt;/em&gt;&lt;/p&gt;</description>
      
    </item>
    
    <item>
      <title>Lexicon</title>
      <link>https://premieres.stephanejacquet.fr/chapters/america/lexicon/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      
      <guid>https://premieres.stephanejacquet.fr/chapters/america/lexicon/</guid>
      <description>&lt;style&gt;&#xA;    .lexicon-list {&#xA;      margin: 1.5rem 0;&#xA;      padding: 0;&#xA;    }&#xA;    .lexicon-list dt {&#xA;      margin: 0;&#xA;      padding: 0;&#xA;      font-weight: 600;&#xA;      font-size: 1.05rem;&#xA;    }&#xA;    .lexicon-list dd {&#xA;      margin: 0.15rem 0 1rem 0;&#xA;      padding: 0;&#xA;      color: inherit;&#xA;      opacity: 0.85;&#xA;    }&#xA;    .lexicon-list dd p {&#xA;      margin: 0;&#xA;    }&#xA;  &lt;/style&gt;&#xA;  &lt;h2&gt;📖 American Identity &amp;mdash; Vocabulary&lt;/h2&gt;&lt;dl class=&#34;lexicon-list&#34;&gt;&#xA;        &lt;dt id=&#34;to-argue&#34;&gt;(to) &lt;span class=&#34;stressed-vowel&#34;&gt;a&lt;/span&gt;rgue&lt;/dt&gt;&#xA;        &lt;dd&gt;se disputer&lt;/dd&gt;&#xA;        &lt;dt id=&#34;to-exemplify&#34;&gt;(to) ex&lt;span class=&#34;stressed-vowel&#34;&gt;e&lt;/span&gt;mplify&lt;/dt&gt;&#xA;        &lt;dd&gt;illustrer&lt;/dd&gt;&#xA;        &lt;dt id=&#34;to-flee&#34;&gt;(to) flee&lt;/dt&gt;&#xA;        &lt;dd&gt;fuir&lt;/dd&gt;&#xA;        &lt;dt id=&#34;to-forgo&#34;&gt;(to) forg&lt;span class=&#34;stressed-vowel&#34;&gt;o&lt;/span&gt;&lt;/dt&gt;&#xA;        &lt;dd&gt;se passer de&lt;/dd&gt;&#xA;        &lt;dt id=&#34;feast&#34;&gt;feast&lt;/dt&gt;&#xA;        &lt;dd&gt;festin&lt;/dd&gt;&#xA;        &lt;dt id=&#34;foothold&#34;&gt;f&lt;span class=&#34;stressed-vowel&#34;&gt;o&lt;/span&gt;&lt;span class=&#34;stressed-vowel&#34;&gt;o&lt;/span&gt;thold&lt;/dt&gt;&#xA;        &lt;dd&gt;poin d&amp;rsquo;appui&lt;/dd&gt;&#xA;        &lt;dt id=&#34;gravitas&#34;&gt;gr&lt;span class=&#34;stressed-vowel&#34;&gt;a&lt;/span&gt;vitas&lt;/dt&gt;&#xA;        &lt;dd&gt;le sérieux&lt;/dd&gt;&#xA;        &lt;dt id=&#34;inadequate&#34;&gt;in&lt;span class=&#34;stressed-vowel&#34;&gt;a&lt;/span&gt;dequate&lt;/dt&gt;&#xA;        &lt;dd&gt;inadéquat(e)&lt;/dd&gt;&#xA;        &lt;dt id=&#34;refugee&#34;&gt;refug&lt;span class=&#34;stressed-vowel&#34;&gt;e&lt;/span&gt;&lt;span class=&#34;stressed-vowel&#34;&gt;e&lt;/span&gt;&lt;/dt&gt;&#xA;        &lt;dd&gt;réfugié&lt;/dd&gt;&#xA;        &lt;dt id=&#34;shelter&#34;&gt;sh&lt;span class=&#34;stressed-vowel&#34;&gt;e&lt;/span&gt;lter&lt;/dt&gt;&#xA;        &lt;dd&gt;abri&lt;/dd&gt;&#xA;        &lt;dt id=&#34;shortage&#34;&gt;sh&lt;span class=&#34;stressed-vowel&#34;&gt;o&lt;/span&gt;rtage&lt;/dt&gt;&#xA;        &lt;dd&gt;pénurie&lt;/dd&gt;&#xA;        &lt;dt id=&#34;soil&#34;&gt;soil&lt;/dt&gt;&#xA;        &lt;dd&gt;territoire&lt;/dd&gt;&#xA;        &lt;dt id=&#34;tale&#34;&gt;tale&lt;/dt&gt;&#xA;        &lt;dd&gt;conte&lt;/dd&gt;&#xA;        &lt;dt id=&#34;turkey&#34;&gt;t&lt;span class=&#34;stressed-vowel&#34;&gt;u&lt;/span&gt;rkey&lt;/dt&gt;&#xA;        &lt;dd&gt;dinde&lt;/dd&gt;&#xA;    &lt;/dl&gt;&#xA;    &lt;p&gt;&#xA;      &lt;a href=&#34;https://premieres.stephanejacquet.fr/chapters/america/&#34;&gt;&amp;larr; Return to American Identity&lt;/a&gt;&#xA;    &lt;/p&gt;</description>
      
    </item>
    
    <item>
      <title>Lexicon</title>
      <link>https://premieres.stephanejacquet.fr/chapters/power_of_english/lexicon/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      
      <guid>https://premieres.stephanejacquet.fr/chapters/power_of_english/lexicon/</guid>
      <description>&lt;style&gt;&#xA;    .lexicon-list {&#xA;      margin: 1.5rem 0;&#xA;      padding: 0;&#xA;    }&#xA;    .lexicon-list dt {&#xA;      margin: 0;&#xA;      padding: 0;&#xA;      font-weight: 600;&#xA;      font-size: 1.05rem;&#xA;    }&#xA;    .lexicon-list dd {&#xA;      margin: 0.15rem 0 1rem 0;&#xA;      padding: 0;&#xA;      color: inherit;&#xA;      opacity: 0.85;&#xA;    }&#xA;    .lexicon-list dd p {&#xA;      margin: 0;&#xA;    }&#xA;  &lt;/style&gt;&#xA;  &lt;h2&gt;📖 The Magic of English &amp;mdash; Vocabulary&lt;/h2&gt;&lt;dl class=&#34;lexicon-list&#34;&gt;&#xA;        &lt;dt id=&#34;adjective&#34;&gt;&lt;span class=&#34;stressed-vowel&#34;&gt;a&lt;/span&gt;djective&lt;/dt&gt;&#xA;        &lt;dd&gt;adjectif&lt;/dd&gt;&#xA;        &lt;dt id=&#34;genitive&#34;&gt;g&lt;span class=&#34;stressed-vowel&#34;&gt;e&lt;/span&gt;nitive&lt;/dt&gt;&#xA;        &lt;dd&gt;génitif&lt;/dd&gt;&#xA;        &lt;dt id=&#34;magical&#34;&gt;m&lt;span class=&#34;stressed-vowel&#34;&gt;a&lt;/span&gt;gical&lt;/dt&gt;&#xA;        &lt;dd&gt;magique&lt;/dd&gt;&#xA;        &lt;dt id=&#34;morphology&#34;&gt;morph&lt;span class=&#34;stressed-vowel&#34;&gt;o&lt;/span&gt;logy&lt;/dt&gt;&#xA;        &lt;dd&gt;The study of word forms&lt;/dd&gt;&#xA;        &lt;dt id=&#34;noun&#34;&gt;noun&lt;/dt&gt;&#xA;        &lt;dd&gt;nom&lt;/dd&gt;&#xA;        &lt;dt id=&#34;plural&#34;&gt;pl&lt;span class=&#34;stressed-vowel&#34;&gt;u&lt;/span&gt;ral&lt;/dt&gt;&#xA;        &lt;dd&gt;pluriel&lt;/dd&gt;&#xA;        &lt;dt id=&#34;power&#34;&gt;p&lt;span class=&#34;stressed-vowel&#34;&gt;o&lt;/span&gt;wer&lt;/dt&gt;&#xA;        &lt;dd&gt;pouvoir&lt;/dd&gt;&#xA;        &lt;dt id=&#34;regular&#34;&gt;r&lt;span class=&#34;stressed-vowel&#34;&gt;e&lt;/span&gt;gular&lt;/dt&gt;&#xA;        &lt;dd&gt;régulier&lt;/dd&gt;&#xA;        &lt;dt id=&#34;verb&#34;&gt;verb&lt;/dt&gt;&#xA;        &lt;dd&gt;verbe&lt;/dd&gt;&#xA;    &lt;/dl&gt;&#xA;    &lt;p&gt;&#xA;      &lt;a href=&#34;https://premieres.stephanejacquet.fr/chapters/power_of_english/&#34;&gt;&amp;larr; Return to The Magic of English&lt;/a&gt;&#xA;    &lt;/p&gt;</description>
      
    </item>
    
    <item>
      <title>Lexicon</title>
      <link>https://premieres.stephanejacquet.fr/chapters/robinson/lexicon/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      
      <guid>https://premieres.stephanejacquet.fr/chapters/robinson/lexicon/</guid>
      <description>&lt;style&gt;&#xA;    .lexicon-list {&#xA;      margin: 1.5rem 0;&#xA;      padding: 0;&#xA;    }&#xA;    .lexicon-list dt {&#xA;      margin: 0;&#xA;      padding: 0;&#xA;      font-weight: 600;&#xA;      font-size: 1.05rem;&#xA;    }&#xA;    .lexicon-list dd {&#xA;      margin: 0.15rem 0 1rem 0;&#xA;      padding: 0;&#xA;      color: inherit;&#xA;      opacity: 0.85;&#xA;    }&#xA;    .lexicon-list dd p {&#xA;      margin: 0;&#xA;    }&#xA;  &lt;/style&gt;&#xA;  &lt;h2&gt;📖 Robinson&amp;#39;s Myth and Avatars &amp;mdash; Vocabulary&lt;/h2&gt;&lt;dl class=&#34;lexicon-list&#34;&gt;&#xA;        &lt;dt id=&#34;to-escape&#34;&gt;(to) esc&lt;span class=&#34;stressed-vowel&#34;&gt;a&lt;/span&gt;pe&lt;/dt&gt;&#xA;        &lt;dd&gt;s&amp;rsquo;échapper&lt;/dd&gt;&#xA;        &lt;dt id=&#34;to-hunt&#34;&gt;(to) hunt&lt;/dt&gt;&#xA;        &lt;dd&gt;chasser&lt;/dd&gt;&#xA;        &lt;dt id=&#34;a-shipwrecked-man&#34;&gt;a sh&lt;span class=&#34;stressed-vowel&#34;&gt;i&lt;/span&gt;pwrecked man&lt;/dt&gt;&#xA;        &lt;dd&gt;un naufragé&lt;/dd&gt;&#xA;        &lt;dt id=&#34;afraid&#34;&gt;afr&lt;span class=&#34;stressed-vowel&#34;&gt;a&lt;/span&gt;&lt;span class=&#34;stressed-vowel&#34;&gt;i&lt;/span&gt;d&lt;/dt&gt;&#xA;        &lt;dd&gt;effrayé&lt;/dd&gt;&#xA;        &lt;dt id=&#34;alone&#34;&gt;al&lt;span class=&#34;stressed-vowel&#34;&gt;o&lt;/span&gt;ne&lt;/dt&gt;&#xA;        &lt;dd&gt;seul&lt;/dd&gt;&#xA;        &lt;dt id=&#34;castaway&#34;&gt;c&lt;span class=&#34;stressed-vowel&#34;&gt;a&lt;/span&gt;staway&lt;/dt&gt;&#xA;        &lt;dd&gt;isolated/cut off from civilisation&lt;/dd&gt;&#xA;        &lt;dt id=&#34;desert-island&#34;&gt;d&lt;span class=&#34;stressed-vowel&#34;&gt;e&lt;/span&gt;sert &lt;span class=&#34;stressed-vowel&#34;&gt;i&lt;/span&gt;sland&lt;/dt&gt;&#xA;        &lt;dd&gt;île déserte&lt;/dd&gt;&#xA;        &lt;dt id=&#34;drinkable-water&#34;&gt;dr&lt;span class=&#34;stressed-vowel&#34;&gt;i&lt;/span&gt;nkable w&lt;span class=&#34;stressed-vowel&#34;&gt;a&lt;/span&gt;ter&lt;/dt&gt;&#xA;        &lt;dd&gt;eau potable&lt;/dd&gt;&#xA;        &lt;dt id=&#34;food-supplies&#34;&gt;f&lt;span class=&#34;stressed-vowel&#34;&gt;o&lt;/span&gt;&lt;span class=&#34;stressed-vowel&#34;&gt;o&lt;/span&gt;d suppl&lt;span class=&#34;stressed-vowel&#34;&gt;i&lt;/span&gt;es&lt;/dt&gt;&#xA;        &lt;dd&gt;réserve de nourriture&lt;/dd&gt;&#xA;        &lt;dt id=&#34;jungle&#34;&gt;j&lt;span class=&#34;stressed-vowel&#34;&gt;u&lt;/span&gt;ngle&lt;/dt&gt;&#xA;        &lt;dd&gt;la jungle&lt;/dd&gt;&#xA;        &lt;dt id=&#34;knife&#34;&gt;knife&lt;/dt&gt;&#xA;        &lt;dd&gt;couteau&lt;/dd&gt;&#xA;        &lt;dt id=&#34;rescue&#34;&gt;r&lt;span class=&#34;stressed-vowel&#34;&gt;e&lt;/span&gt;scue&lt;/dt&gt;&#xA;        &lt;dd&gt;secourir&lt;/dd&gt;&#xA;        &lt;dt id=&#34;rope&#34;&gt;rope&lt;/dt&gt;&#xA;        &lt;dd&gt;corde&lt;/dd&gt;&#xA;        &lt;dt id=&#34;shelter&#34;&gt;sh&lt;span class=&#34;stressed-vowel&#34;&gt;e&lt;/span&gt;lter&lt;/dt&gt;&#xA;        &lt;dd&gt;abri&lt;/dd&gt;&#xA;        &lt;dt id=&#34;shipwreck&#34;&gt;sh&lt;span class=&#34;stressed-vowel&#34;&gt;i&lt;/span&gt;pwreck&lt;/dt&gt;&#xA;        &lt;dd&gt;naufrage&lt;/dd&gt;&#xA;        &lt;dt id=&#34;storm&#34;&gt;storm&lt;/dt&gt;&#xA;        &lt;dd&gt;tempête&lt;/dd&gt;&#xA;        &lt;dt id=&#34;survival&#34;&gt;surv&lt;span class=&#34;stressed-vowel&#34;&gt;i&lt;/span&gt;val&lt;/dt&gt;&#xA;        &lt;dd&gt;survie&lt;/dd&gt;&#xA;        &lt;dt id=&#34;the-wild--wilderness&#34;&gt;the wild / w&lt;span class=&#34;stressed-vowel&#34;&gt;i&lt;/span&gt;lderness&lt;/dt&gt;&#xA;        &lt;dd&gt;la nature sauvage&lt;/dd&gt;&#xA;        &lt;dt id=&#34;weapon&#34;&gt;w&lt;span class=&#34;stressed-vowel&#34;&gt;e&lt;/span&gt;&lt;span class=&#34;stressed-vowel&#34;&gt;a&lt;/span&gt;pon&lt;/dt&gt;&#xA;        &lt;dd&gt;arme&lt;/dd&gt;&#xA;    &lt;/dl&gt;&#xA;    &lt;p&gt;&#xA;      &lt;a href=&#34;https://premieres.stephanejacquet.fr/chapters/robinson/&#34;&gt;&amp;larr; Return to Robinson&amp;#39;s Myth and Avatars&lt;/a&gt;&#xA;    &lt;/p&gt;</description>
      
    </item>
    
    <item>
      <title>Lexicon</title>
      <link>https://premieres.stephanejacquet.fr/chapters/women_detectives/lexicon/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      
      <guid>https://premieres.stephanejacquet.fr/chapters/women_detectives/lexicon/</guid>
      <description>&lt;style&gt;&#xA;    .lexicon-list {&#xA;      margin: 1.5rem 0;&#xA;      padding: 0;&#xA;    }&#xA;    .lexicon-list dt {&#xA;      margin: 0;&#xA;      padding: 0;&#xA;      font-weight: 600;&#xA;      font-size: 1.05rem;&#xA;    }&#xA;    .lexicon-list dd {&#xA;      margin: 0.15rem 0 1rem 0;&#xA;      padding: 0;&#xA;      color: inherit;&#xA;      opacity: 0.85;&#xA;    }&#xA;    .lexicon-list dd p {&#xA;      margin: 0;&#xA;    }&#xA;  &lt;/style&gt;&#xA;  &lt;h2&gt;📖 Women Detectives &amp;mdash; Vocabulary&lt;/h2&gt;&lt;dl class=&#34;lexicon-list&#34;&gt;&#xA;        &lt;dt id=&#34;to-gossip&#34;&gt;g&lt;span class=&#34;stressed-vowel&#34;&gt;o&lt;/span&gt;ssip&lt;/dt&gt;&#xA;        &lt;dd&gt;(to) talk about other people&amp;rsquo;s private business behind their back&lt;/dd&gt;&#xA;        &lt;dt id=&#34;to-miss&#34;&gt;(to) miss&lt;/dt&gt;&#xA;        &lt;dd&gt;to not see, hear, or notice something&lt;/dd&gt;&#xA;        &lt;dt id=&#34;to-notice&#34;&gt;(to) n&lt;span class=&#34;stressed-vowel&#34;&gt;o&lt;/span&gt;tice&lt;/dt&gt;&#xA;        &lt;dd&gt;if you notice something or someone, you realise they exist&lt;/dd&gt;&#xA;        &lt;dt id=&#34;to-shave&#34;&gt;(to) shave&lt;/dt&gt;&#xA;        &lt;dd&gt;(to) cut off hair very close using a razor&lt;/dd&gt;&#xA;        &lt;dt id=&#34;to-solve-a-crime&#34;&gt;(to) s&lt;span class=&#34;stressed-vowel&#34;&gt;o&lt;/span&gt;lve a cr&lt;span class=&#34;stressed-vowel&#34;&gt;i&lt;/span&gt;me&lt;/dt&gt;&#xA;        &lt;dd&gt;&lt;/dd&gt;&#xA;        &lt;dt id=&#34;to-turn-the-tables&#34;&gt;(to) t&lt;span class=&#34;stressed-vowel&#34;&gt;u&lt;/span&gt;rn the t&lt;span class=&#34;stressed-vowel&#34;&gt;a&lt;/span&gt;bles&lt;/dt&gt;&#xA;        &lt;dd&gt;if you turn the tables, you reverse a situation to your advantage&lt;/dd&gt;&#xA;        &lt;dt id=&#34;active&#34;&gt;&lt;span class=&#34;stressed-vowel&#34;&gt;a&lt;/span&gt;ctive&lt;/dt&gt;&#xA;        &lt;dd&gt;≠ passive&lt;/dd&gt;&#xA;        &lt;dt id=&#34;cunning&#34;&gt;c&lt;span class=&#34;stressed-vowel&#34;&gt;u&lt;/span&gt;nning&lt;/dt&gt;&#xA;        &lt;dd&gt;clever&lt;/dd&gt;&#xA;        &lt;dt id=&#34;determined&#34;&gt;det&lt;span class=&#34;stressed-vowel&#34;&gt;e&lt;/span&gt;rmined&lt;/dt&gt;&#xA;        &lt;dd&gt;showing determination&lt;/dd&gt;&#xA;        &lt;dt id=&#34;downsize&#34;&gt;d&lt;span class=&#34;stressed-vowel&#34;&gt;o&lt;/span&gt;&lt;span class=&#34;stressed-vowel&#34;&gt;w&lt;/span&gt;nsize&lt;/dt&gt;&#xA;        &lt;dd&gt;(to) make smaller&lt;/dd&gt;&#xA;        &lt;dt id=&#34;equal&#34;&gt;&lt;span class=&#34;stressed-vowel&#34;&gt;e&lt;/span&gt;qual&lt;/dt&gt;&#xA;        &lt;dd&gt;≠ unequal&lt;/dd&gt;&#xA;        &lt;dt id=&#34;evidence&#34;&gt;&lt;span class=&#34;stressed-vowel&#34;&gt;e&lt;/span&gt;vidence&lt;/dt&gt;&#xA;        &lt;dd&gt;proof&lt;/dd&gt;&#xA;        &lt;dt id=&#34;gossip&#34;&gt;g&lt;span class=&#34;stressed-vowel&#34;&gt;o&lt;/span&gt;ssip&lt;/dt&gt;&#xA;        &lt;dd&gt;une commmère&lt;/dd&gt;&#xA;        &lt;dt id=&#34;insufferable&#34;&gt;ins&lt;span class=&#34;stressed-vowel&#34;&gt;u&lt;/span&gt;fferable&lt;/dt&gt;&#xA;        &lt;dd&gt;extremely annoying or unpleasant&lt;/dd&gt;&#xA;        &lt;dt id=&#34;investigation&#34;&gt;inv&lt;span class=&#34;stressed-vowel&#34;&gt;e&lt;/span&gt;stig&lt;span class=&#34;stressed-vowel&#34;&gt;a&lt;/span&gt;tion&lt;/dt&gt;&#xA;        &lt;dd&gt;enquiry&lt;/dd&gt;&#xA;        &lt;dt id=&#34;menial&#34;&gt;m&lt;span class=&#34;stressed-vowel&#34;&gt;e&lt;/span&gt;nial&lt;/dt&gt;&#xA;        &lt;dd&gt;menial work is boring, needs no skill, and is not important&lt;/dd&gt;&#xA;        &lt;dt id=&#34;professional&#34;&gt;prof&lt;span class=&#34;stressed-vowel&#34;&gt;e&lt;/span&gt;ssional&lt;/dt&gt;&#xA;        &lt;dd&gt;≠ amateur&lt;/dd&gt;&#xA;        &lt;dt id=&#34;proper&#34;&gt;pr&lt;span class=&#34;stressed-vowel&#34;&gt;o&lt;/span&gt;per&lt;/dt&gt;&#xA;        &lt;dd&gt;the real or of good standards&lt;/dd&gt;&#xA;        &lt;dt id=&#34;set&#34;&gt;set&lt;/dt&gt;&#xA;        &lt;dd&gt;if a film or story is set in a particular place or period, the aciton is taking place there or then.&lt;/dd&gt;&#xA;        &lt;dt id=&#34;skill&#34;&gt;skill&lt;/dt&gt;&#xA;        &lt;dd&gt;the ability to do something well because you have learned or practised it&lt;/dd&gt;&#xA;        &lt;dt id=&#34;spinster&#34;&gt;sp&lt;span class=&#34;stressed-vowel&#34;&gt;i&lt;/span&gt;nster&lt;/dt&gt;&#xA;        &lt;dd&gt;an unmarried women, usually one who is no longer young and seems unlikely to marry&lt;/dd&gt;&#xA;        &lt;dt id=&#34;traditional&#34;&gt;trad&lt;span class=&#34;stressed-vowel&#34;&gt;i&lt;/span&gt;tional&lt;/dt&gt;&#xA;        &lt;dd&gt;≠ modern&lt;/dd&gt;&#xA;        &lt;dt id=&#34;unconventional&#34;&gt;&lt;span class=&#34;stressed-vowel&#34;&gt;u&lt;/span&gt;nconv&lt;span class=&#34;stressed-vowel&#34;&gt;e&lt;/span&gt;ntional&lt;/dt&gt;&#xA;        &lt;dd&gt;unusual&lt;/dd&gt;&#xA;        &lt;dt id=&#34;unfair&#34;&gt;unf&lt;span class=&#34;stressed-vowel&#34;&gt;a&lt;/span&gt;&lt;span class=&#34;stressed-vowel&#34;&gt;i&lt;/span&gt;r&lt;/dt&gt;&#xA;        &lt;dd&gt;unjust&lt;/dd&gt;&#xA;    &lt;/dl&gt;&#xA;    &lt;p&gt;&#xA;      &lt;a href=&#34;https://premieres.stephanejacquet.fr/chapters/women_detectives/&#34;&gt;&amp;larr; Return to Women Detectives&lt;/a&gt;&#xA;    &lt;/p&gt;</description>
      
    </item>
    
    <item>
      <title>Flashcards</title>
      <link>https://premieres.stephanejacquet.fr/chapters/aborigines/flashcards/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      
      <guid>https://premieres.stephanejacquet.fr/chapters/aborigines/flashcards/</guid>
      <description>&lt;div class=&#34;flashcards-empty&#34; style=&#34;padding:2rem;border:1px dashed #bbb;border-radius:8px;text-align:center;color:#666;&#34;&gt;&#xA;  &lt;h2&gt;🧠 Aboriginal Dreams - Australian Lands &amp;mdash; Flashcards&lt;/h2&gt;&#xA;  &lt;p&gt;No vocabulary has been added to this unit yet.&lt;/p&gt;&#xA;  &lt;p style=&#34;font-size:0.9rem;&#34;&gt;Add entries under &lt;code&gt;lexicon:&lt;/code&gt; in the unit&#39;s &lt;code&gt;_index.md&lt;/code&gt; to activate the flashcards.&lt;/p&gt;&#xA;&lt;/div&gt;</description>
      
    </item>
    
    <item>
      <title>Flashcards</title>
      <link>https://premieres.stephanejacquet.fr/chapters/america/flashcards/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      
      <guid>https://premieres.stephanejacquet.fr/chapters/america/flashcards/</guid>
      <description>&lt;div class=&#34;flashcards-container&#34;&gt;&#xA;&lt;div style=&#34;display:flex; justify-content:space-between; align-items:baseline; gap:1rem; flex-wrap:wrap;&#34;&gt;&#xA;&lt;h2&gt;🧠 American Identity &amp;mdash; Flashcards&lt;/h2&gt;&#xA;&lt;a href=&#34;https://premieres.stephanejacquet.fr/login/&#34; id=&#34;auth-link&#34; class=&#34;login-link&#34; style=&#34;color:#007bff; text-decoration:none; font-size:0.9rem; white-space:nowrap;&#34;&gt;Login&lt;/a&gt;&#xA;&lt;/div&gt;&#xA;&lt;div class=&#34;flashcards-header&#34;&gt;&#xA;&lt;div class=&#34;flashcards-controls&#34;&gt;&#xA;&lt;div class=&#34;mode-selector&#34;&gt;&#xA;&lt;label class=&#34;mode-option&#34;&gt;&#xA;&lt;input type=&#34;radio&#34; name=&#34;study-mode&#34; value=&#34;term-to-definition&#34; checked&gt;&#xA;&lt;span&gt;Term → Definition&lt;/span&gt;&#xA;&lt;/label&gt;&#xA;&lt;label class=&#34;mode-option&#34;&gt;&#xA;&lt;input type=&#34;radio&#34; name=&#34;study-mode&#34; value=&#34;definition-to-term&#34;&gt;&#xA;&lt;span&gt;Definition → Term&lt;/span&gt;&#xA;&lt;/label&gt;&#xA;&lt;/div&gt;&#xA;&lt;div class=&#34;control-buttons&#34;&gt;&#xA;&lt;button id=&#34;mode-toggle-btn&#34; class=&#34;btn btn-secondary&#34;&gt;📖 Browse&lt;/button&gt;&#xA;&lt;button id=&#34;early-review-btn&#34; class=&#34;btn btn-info&#34;&gt;⏰ Early Review&lt;/button&gt;&#xA;&lt;button id=&#34;reset-progress&#34; class=&#34;btn btn-outline&#34;&gt;🔄 Reset&lt;/button&gt;&#xA;&lt;/div&gt;&#xA;&lt;div class=&#34;progress-display&#34;&gt;&#xA;&lt;span id=&#34;current-card&#34;&gt;1&lt;/span&gt; / &lt;span id=&#34;total-cards&#34;&gt;14&lt;/span&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&#xA;&lt;div class=&#34;flashcard-wrapper&#34;&gt;&#xA;&lt;div class=&#34;flashcard&#34; id=&#34;flashcard&#34;&gt;&#xA;&lt;div class=&#34;flashcard-inner&#34;&gt;&#xA;&lt;div class=&#34;flashcard-front&#34;&gt;&#xA;&lt;div class=&#34;card-content&#34;&gt;&#xA;&lt;div class=&#34;question&#34; id=&#34;card-question&#34;&gt;&lt;/div&gt;&#xA;&lt;div class=&#34;card-hint&#34;&gt;Tap to reveal answer&lt;/div&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&#xA;&lt;div class=&#34;flashcard-back&#34;&gt;&#xA;&lt;div class=&#34;card-content&#34;&gt;&#xA;&lt;div class=&#34;question-small&#34; id=&#34;card-question-back&#34;&gt;&lt;/div&gt;&#xA;&lt;div class=&#34;answer&#34; id=&#34;card-answer&#34;&gt;&lt;/div&gt;&#xA;&lt;div class=&#34;card-hint&#34;&gt;Tap to flip back&lt;/div&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&#xA;&lt;div class=&#34;flashcards-navigation&#34;&gt;&#xA;&lt;div class=&#34;nav-top&#34;&gt;&#xA;&lt;button id=&#34;next-btn&#34; class=&#34;btn btn-primary&#34;&gt;Next →&lt;/button&gt;&#xA;&lt;/div&gt;&#xA;&lt;div class=&#34;nav-middle&#34;&gt;&#xA;&lt;div class=&#34;difficulty-buttons&#34;&gt;&#xA;&lt;button id=&#34;again-btn&#34; class=&#34;btn btn-danger-dark&#34;&gt;🚫 Again&lt;/button&gt;&#xA;&lt;button id=&#34;hard-btn&#34; class=&#34;btn btn-danger&#34;&gt;😰 Hard&lt;/button&gt;&#xA;&lt;button id=&#34;medium-btn&#34; class=&#34;btn btn-warning&#34;&gt;🤔 Medium&lt;/button&gt;&#xA;&lt;button id=&#34;easy-btn&#34; class=&#34;btn btn-success&#34;&gt;😊 Easy&lt;/button&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&#xA;&lt;div class=&#34;nav-bottom&#34;&gt;&#xA;&lt;button id=&#34;prev-btn&#34; class=&#34;btn btn-primary&#34;&gt;← Previous&lt;/button&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&#xA;&lt;div class=&#34;progress-stats&#34;&gt;&#xA;&lt;div class=&#34;stat&#34;&gt;&#xA;&lt;span class=&#34;stat-label&#34;&gt;Reviewed:&lt;/span&gt;&#xA;&lt;span id=&#34;reviewed-count&#34;&gt;0&lt;/span&gt;&#xA;&lt;/div&gt;&#xA;&lt;div class=&#34;stat&#34;&gt;&#xA;&lt;span class=&#34;stat-label&#34;&gt;Again:&lt;/span&gt;&#xA;&lt;span id=&#34;again-count&#34;&gt;0&lt;/span&gt;&#xA;&lt;/div&gt;&#xA;&lt;div class=&#34;stat&#34;&gt;&#xA;&lt;span class=&#34;stat-label&#34;&gt;Hard:&lt;/span&gt;&#xA;&lt;span id=&#34;hard-count&#34;&gt;0&lt;/span&gt;&#xA;&lt;/div&gt;&#xA;&lt;div class=&#34;stat&#34;&gt;&#xA;&lt;span class=&#34;stat-label&#34;&gt;Medium:&lt;/span&gt;&#xA;&lt;span id=&#34;medium-count&#34;&gt;0&lt;/span&gt;&#xA;&lt;/div&gt;&#xA;&lt;div class=&#34;stat&#34;&gt;&#xA;&lt;span class=&#34;stat-label&#34;&gt;Easy:&lt;/span&gt;&#xA;&lt;span id=&#34;easy-count&#34;&gt;0&lt;/span&gt;&#xA;&lt;/div&gt;&#xA;&lt;div class=&#34;stat&#34;&gt;&#xA;&lt;span class=&#34;stat-label&#34;&gt;Due:&lt;/span&gt;&#xA;&lt;span id=&#34;review-count&#34;&gt;0&lt;/span&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&#xA;&lt;div class=&#34;completion-message&#34; id=&#34;completion-message&#34; style=&#34;display: none;&#34;&gt;&#xA;&lt;div class=&#34;completion-content&#34;&gt;&#xA;&lt;div class=&#34;completion-icon&#34;&gt;🎉&lt;/div&gt;&#xA;&lt;h3 class=&#34;completion-title&#34;&gt;Great Job!&lt;/h3&gt;&#xA;&lt;p class=&#34;completion-text&#34; id=&#34;completion-text&#34;&gt;&lt;/p&gt;&#xA;&lt;div class=&#34;completion-actions&#34;&gt;&#xA;&lt;button id=&#34;early-review-option&#34; class=&#34;btn btn-info&#34; style=&#34;display: none;&#34;&gt;⏰ Review Early Cards&lt;/button&gt;&#xA;&lt;button id=&#34;browse-all-option&#34; class=&#34;btn btn-secondary&#34;&gt;📖 Browse All Cards&lt;/button&gt;&#xA;&lt;button id=&#34;close-completion&#34; class=&#34;btn btn-primary&#34;&gt;✨ Done&lt;/button&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&#xA;&lt;style&gt;&#xA; &#xA;.stressed-vowel {&#xA;color: red !important;&#xA;font-weight: bold;&#xA;}&#xA; &#xA;.btn-danger-dark {&#xA;background: #8b0000;&#xA;color: white;&#xA;}&#xA;.btn-danger-dark:hover {&#xA;background: #a00000;&#xA;transform: translateY(-1px);&#xA;box-shadow: 0 2px 8px rgba(0,0,0,0.2);&#xA;}&#xA; &#xA;.flashcards-container {&#xA;max-width: 600px;&#xA;margin: 0 auto;&#xA;padding: 1rem;&#xA;font-family: -apple-system, BlinkMacSystemFont, &#39;Segoe UI&#39;, Roboto, sans-serif;&#xA;display: flex;&#xA;flex-direction: column;&#xA;box-sizing: border-box;&#xA;gap: 1rem;&#xA;}&#xA;.flashcards-header {&#xA;display: flex;&#xA;justify-content: space-between;&#xA;align-items: center;&#xA;margin-bottom: 1rem;&#xA;flex-wrap: wrap;&#xA;gap: 1rem;&#xA;}&#xA;.flashcards-header h3 {&#xA;margin: 0;&#xA;color: inherit;&#xA;font-size: clamp(1.2rem, 4vw, 1.5rem);&#xA;}&#xA;.flashcards-controls {&#xA;display: flex;&#xA;align-items: center;&#xA;gap: 1.2rem;&#xA;flex-wrap: wrap;&#xA;padding: 0.5rem 0;&#xA;}&#xA;.mode-selector {&#xA;display: flex;&#xA;gap: 0.8rem;&#xA;align-items: center;&#xA;}&#xA;.mode-option {&#xA;display: flex;&#xA;align-items: center;&#xA;gap: 0.5rem;&#xA;cursor: pointer;&#xA;padding: 0.5rem 0.75rem;&#xA;border-radius: 20px;&#xA;background: #f8f9fa;&#xA;border: 1px solid #ced4da;&#xA;color: #212529;&#xA;transition: all 0.2s ease;&#xA;font-size: clamp(0.75rem, 3vw, 0.9rem);&#xA;white-space: nowrap;&#xA;}&#xA;.mode-option span {&#xA;color: #212529;&#xA;}&#xA;.mode-option:hover {&#xA;background: #e9ecef;&#xA;}&#xA;.mode-option input[type=&#34;radio&#34;] {&#xA;margin: 0;&#xA;}&#xA;.mode-option input[type=&#34;radio&#34;]:checked + span {&#xA;font-weight: bold;&#xA;color: #007bff;&#xA;}&#xA;.control-buttons {&#xA;display: flex;&#xA;gap: 0.8rem;&#xA;}&#xA;.progress-display {&#xA;background: #f5f5f5;&#xA;padding: 0.5rem 0.75rem;&#xA;border-radius: 20px;&#xA;border: 1px solid #ced4da;&#xA;font-weight: bold;&#xA;color: #212529;&#xA;font-size: clamp(0.8rem, 3vw, 0.9rem);&#xA;}&#xA;.flashcard-wrapper {&#xA;perspective: 1000px;&#xA;margin: 1.5rem 0;&#xA;display: flex;&#xA;align-items: center;&#xA;}&#xA;.flashcard {&#xA;width: 100%;&#xA;height: clamp(220px, 35vh, 320px);&#xA;position: relative;&#xA;cursor: pointer;&#xA;transition: transform 0.3s ease;&#xA;}&#xA;.flashcard:hover {&#xA;transform: translateY(-2px);&#xA;}&#xA;.flashcard-inner {&#xA;position: relative;&#xA;width: 100%;&#xA;height: 100%;&#xA;text-align: center;&#xA;transition: transform 0.6s;&#xA;transform-style: preserve-3d;&#xA;}&#xA;.flashcard.flipped .flashcard-inner {&#xA;transform: rotateY(180deg);&#xA;}&#xA;.flashcard-front, .flashcard-back {&#xA;position: absolute;&#xA;width: 100%;&#xA;height: 100%;&#xA;backface-visibility: hidden;&#xA;border-radius: 15px;&#xA;box-shadow: 0 4px 20px rgba(0,0,0,0.1);&#xA;display: flex;&#xA;align-items: center;&#xA;justify-content: center;&#xA;}&#xA;.flashcard-front {&#xA;background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);&#xA;color: white;&#xA;}&#xA;.flashcard-back {&#xA;background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);&#xA;color: white;&#xA;transform: rotateY(180deg);&#xA;}&#xA;.card-content {&#xA;padding: clamp(1.5rem, 5vw, 2.5rem);&#xA;width: 100%;&#xA;height: 100%;&#xA;display: flex;&#xA;flex-direction: column;&#xA;justify-content: center;&#xA;box-sizing: border-box;&#xA;overflow: hidden;&#xA;}&#xA;&#xA; &#xA;.term, .question {&#xA;    font-size: clamp(1.4rem, 5vw, 2rem);&#xA;    font-weight: bold;&#xA;    margin-bottom: 1rem;&#xA;    text-shadow: 0 2px 4px rgba(0,0,0,0.3);&#xA;    line-height: 1.3;&#xA;    overflow-wrap: break-word;&#xA;    hyphens: auto;&#xA;    display: flex;&#xA;    align-items: center;&#xA;    justify-content: center;&#xA;    text-align: center;&#xA;    height: 100%;&#xA;    margin: 0 auto;&#xA;     &#xA;    white-space: pre-wrap;&#xA;}&#xA;&#xA;&#xA;&#xA;&#xA;&#xA;&#xA;&#xA;.term-small, .question-small {&#xA;font-size: clamp(0.85rem, 3.2vw, 1.1rem);&#xA;font-weight: bold;&#xA;margin-bottom: 0.75rem;&#xA;opacity: 0.8;&#xA;line-height: 1.3;&#xA;overflow-wrap: break-word;&#xA;text-align: center;&#xA;}&#xA;.definition, .answer {&#xA;font-size: clamp(1.4rem, 5vw, 2rem);&#xA;font-weight: bold;&#xA;margin-bottom: 1rem;&#xA;text-shadow: 0 2px 4px rgba(0,0,0,0.3);&#xA;line-height: 1.3;&#xA;overflow-wrap: break-word;&#xA;hyphens: auto;&#xA;flex: 1;&#xA;display: flex;&#xA;align-items: center;&#xA;justify-content: center;&#xA;text-align: center;&#xA;}&#xA;.card-hint {&#xA;font-size: clamp(0.7rem, 2.3vw, 0.85rem);&#xA;opacity: 0.7;&#xA;font-style: italic;&#xA;margin-top: auto;&#xA;text-align: center;&#xA;}&#xA;.flashcards-navigation {&#xA;display: flex;&#xA;flex-direction: column;&#xA;gap: 0.75rem;&#xA;margin: 1.5rem 0;&#xA;}&#xA;.nav-top, .nav-bottom {&#xA;display: flex;&#xA;justify-content: center;&#xA;}&#xA;.nav-middle {&#xA;display: flex;&#xA;justify-content: center;&#xA;}&#xA;.difficulty-buttons {&#xA;display: flex;&#xA;gap: 0.8rem;&#xA;justify-content: center;&#xA;flex-wrap: wrap;&#xA;}&#xA;.btn {&#xA;padding: clamp(0.4rem, 1.8vw, 0.6rem) clamp(0.8rem, 2.5vw, 1rem);&#xA;border: none;&#xA;border-radius: 8px;&#xA;cursor: pointer;&#xA;font-weight: 500;&#xA;transition: all 0.2s ease;&#xA;font-size: clamp(0.75rem, 2.8vw, 0.85rem);&#xA;white-space: nowrap;&#xA;min-width: fit-content;&#xA;}&#xA;.btn:hover {&#xA;transform: translateY(-1px);&#xA;box-shadow: 0 2px 8px rgba(0,0,0,0.2);&#xA;}&#xA;.btn-primary { background: #007bff; color: white; }&#xA;.btn-secondary { background: #6c757d; color: white; }&#xA;.btn-secondary:hover { background: #5a6268; }&#xA;.btn-success { background: #28a745; color: white; }&#xA;.btn-warning { background: #ffc107; color: #212529; }&#xA;.btn-danger { background: #dc3545; color: white; }&#xA;.btn-outline { background: white; border: 2px solid #495057; color: #212529; }&#xA;.btn-outline:hover { background: #495057; color: white; }&#xA;.btn-info { background: #17a2b8; color: white; }&#xA;.btn-info:hover { background: #138496; }&#xA;.btn:disabled {&#xA;opacity: 0.5;&#xA;cursor: not-allowed;&#xA;transform: none;&#xA;}&#xA;.progress-stats {&#xA;display: grid;&#xA;grid-template-columns: repeat(auto-fit, minmax(70px, 1fr));&#xA;gap: 0.75rem;&#xA;background: #f8f9fa;&#xA;border: 1px solid #ced4da;&#xA;padding: 0.75rem;&#xA;border-radius: 10px;&#xA;margin-top: 1rem;&#xA;}&#xA;.stat {&#xA;text-align: center;&#xA;flex: 1;&#xA;min-width: 70px;&#xA;}&#xA;.stat-label {&#xA;display: block;&#xA;font-size: clamp(0.65rem, 2.3vw, 0.75rem);&#xA;color: #666;&#xA;text-transform: uppercase;&#xA;letter-spacing: 0.5px;&#xA;}&#xA;.stat span:last-child {&#xA;display: block;&#xA;font-size: clamp(1rem, 3.5vw, 1.3rem);&#xA;font-weight: bold;&#xA;color: #333;&#xA;margin-top: 0.25rem;&#xA;}&#xA;.completion-message {&#xA;position: fixed;&#xA;top: 0;&#xA;left: 0;&#xA;width: 100%;&#xA;height: 100%;&#xA;background: rgba(0, 0, 0, 0.8);&#xA;display: flex;&#xA;align-items: center;&#xA;justify-content: center;&#xA;z-index: 1000;&#xA;backdrop-filter: blur(5px);&#xA;}&#xA;.completion-content {&#xA;background: white;&#xA;padding: 2rem;&#xA;border-radius: 20px;&#xA;text-align: center;&#xA;max-width: 90%;&#xA;max-height: 90%;&#xA;overflow-y: auto;&#xA;box-shadow: 0 20px 40px rgba(0, 0, 0, 0.3);&#xA;animation: completionSlideIn 0.3s ease-out;&#xA;}&#xA;@keyframes completionSlideIn {&#xA;from {&#xA;opacity: 0;&#xA;transform: translateY(-50px) scale(0.9);&#xA;}&#xA;to {&#xA;opacity: 1;&#xA;transform: translateY(0) scale(1);&#xA;}&#xA;}&#xA;.completion-icon {&#xA;font-size: 4rem;&#xA;margin-bottom: 1rem;&#xA;animation: bounce 1s ease-in-out infinite alternate;&#xA;}&#xA;@keyframes bounce {&#xA;from { transform: translateY(0); }&#xA;to { transform: translateY(-10px); }&#xA;}&#xA;.completion-title {&#xA;color: #333;&#xA;margin-bottom: 1rem;&#xA;font-size: 2rem;&#xA;font-weight: bold;&#xA;}&#xA;.completion-text {&#xA;color: #666;&#xA;margin-bottom: 2rem;&#xA;font-size: 1.1rem;&#xA;line-height: 1.5;&#xA;}&#xA;.completion-actions {&#xA;display: flex;&#xA;gap: 1rem;&#xA;justify-content: center;&#xA;flex-wrap: wrap;&#xA;}&#xA;.completion-actions .btn {&#xA;min-width: 120px;&#xA;}&#xA; &#xA;@media (max-width: 768px) {&#xA;.flashcards-container { padding: 0.75rem; gap: 0.75rem; }&#xA;.flashcards-header { flex-direction: column; align-items: flex-start; margin-bottom: 0.75rem; gap: 0.75rem; }&#xA;.flashcards-controls { flex-direction: column; align-items: flex-start; gap: 0.75rem; width: 100%; }&#xA;.mode-selector { width: 100%; justify-content: flex-start; }&#xA;.control-buttons { width: 100%; justify-content: flex-start; }&#xA;.progress-display { align-self: flex-start; }&#xA;.flashcard { height: clamp(180px, 30vh, 250px); }&#xA;.flashcard-wrapper { margin: 1rem 0; }&#xA;.flashcards-navigation { margin: 1rem 0; gap: 0.5rem; }&#xA;.card-content { padding: clamp(1.2rem, 4vw, 2rem); }&#xA;.difficulty-buttons { gap: 0.5rem; }&#xA;.progress-stats { grid-template-columns: repeat(3, 1fr); gap: 0.5rem; }&#xA;}&#xA;@media (max-width: 480px) {&#xA;.flashcards-container { padding: 0.5rem; }&#xA;.flashcard { height: clamp(150px, 28vh, 220px); }&#xA;.flashcard-wrapper { margin: 0.75rem 0; }&#xA;.flashcards-navigation { margin: 0.75rem 0; }&#xA;.card-content { padding: clamp(1rem, 3.5vw, 1.5rem); }&#xA;.completion-content { padding: 1.5rem; margin: 1rem; }&#xA;.completion-icon { font-size: 3rem; }&#xA;.completion-title { font-size: 1.5rem; }&#xA;.completion-text { font-size: 1rem; }&#xA;.completion-actions { flex-direction: column; align-items: center; }&#xA;.completion-actions .btn { width: 100%; max-width: 200px; }&#xA;.progress-stats { grid-template-columns: repeat(2, 1fr); }&#xA;.difficulty-buttons { flex-wrap: wrap; gap: 0.3rem; }&#xA;.difficulty-buttons .btn { flex: 1; min-width: 60px; font-size: 0.7rem; padding: 0.3rem 0.5rem; }&#xA; &#xA;.difficulty-buttons .btn { text-indent: -1ch; overflow: hidden; white-space: nowrap; }&#xA;}&#xA;@media (max-height: 500px) and (orientation: landscape) {&#xA;.flashcard { height: clamp(120px, 45vh, 180px); }&#xA;.flashcard-wrapper { margin: 0.5rem 0; }&#xA;.flashcards-navigation { margin: 0.5rem 0; gap: 0.3rem; }&#xA;.flashcards-header h3 { font-size: 1rem; }&#xA;.progress-stats { padding: 0.5rem; }&#xA;.card-content { padding: clamp(0.8rem, 3vw, 1.2rem); }&#xA;}&#xA;&lt;/style&gt;&#xA;&lt;script src=&#34;https://unpkg.com/@supabase/supabase-js@2&#34;&gt;&lt;/script&gt;&#xA;&lt;script&gt;&#xA;&#xA;const { createClient } = supabase;&#xA;const supabaseClient = createClient(&#xA;&#39;https://xjurrqzjvhzjweufgivl.supabase.co&#39;,&#xA;&#39;eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6InhqdXJycXpqdmh6andldWZnaXZsIiwicm9sZSI6ImFub24iLCJpYXQiOjE3NDg5NDUzMTIsImV4cCI6MjA2NDUyMTMxMn0.rimZk-g9-RmvQCbQJ5Phk0lKwOue6pPlgibO-LKHqmM&#39;&#xA;);&#xA;&#xA;let authCheckInProgress = false;&#xA;let lastAuthCheck = 0;&#xA;const AUTH_CHECK_THROTTLE = 5000; &#xA;async function updateAuthLink() {&#xA;const now = Date.now();&#xA;if (authCheckInProgress || (now - lastAuthCheck) &lt; AUTH_CHECK_THROTTLE) {&#xA;return; &#xA;}&#xA;authCheckInProgress = true;&#xA;lastAuthCheck = now;&#xA;const authLink = document.getElementById(&#39;auth-link&#39;);&#xA;if (!authLink) {&#xA;authCheckInProgress = false;&#xA;return;&#xA;}&#xA;try {&#xA;const { data: { session }, error } = await supabaseClient.auth.getSession();&#xA;if (error || !session?.user) {&#xA;authLink.textContent = &#39;Login&#39;;&#xA;authLink.href = &#39;/login/&#39;;&#xA;authLink.onclick = null;&#xA;return;&#xA;}&#xA;authLink.textContent = &#39;Logout&#39;;&#xA;authLink.onclick = async function(e) {&#xA;e.preventDefault();&#xA;try {&#xA;await supabaseClient.auth.signOut();&#xA;window.location.reload();&#xA;} catch (err) {&#xA;window.location.reload();&#xA;}&#xA;};&#xA;} catch (err) {&#xA;authLink.textContent = &#39;Login&#39;;&#xA;authLink.href = &#39;/login/&#39;;&#xA;authLink.onclick = null;&#xA;} finally {&#xA;authCheckInProgress = false;&#xA;}&#xA;}&#xA;&#xA;class FlashcardSystem {&#xA;constructor() {&#xA;&#xA;this.flashcards = [&#xA;&#xA;&#xA;{&#xA;term: &#34;\&#34;refugee\&#34;&#34;,&#xA;definition: &#34;\&#34;réfugié\&#34;&#34;,&#xA;stressed: &#34;\&#34;refug*e*e\&#34;&#34;,&#xA;id: &#34;\&#34;8ed58fd592b6ccdb3223b2cfdb3f2deace072043143fb2f298e4b5e8e355a24e\&#34;&#34;&#xA;},&#xA;&#xA;&#xA;&#xA;{&#xA;term: &#34;\&#34;shortage\&#34;&#34;,&#xA;definition: &#34;\&#34;pénurie\&#34;&#34;,&#xA;stressed: &#34;\&#34;sh*ortage\&#34;&#34;,&#xA;id: &#34;\&#34;867f393ba8b496be6d3128ccfbe1195a0129896d07335be1d589e6e04e22b136\&#34;&#34;&#xA;},&#xA;&#xA;&#xA;&#xA;{&#xA;term: &#34;\&#34;turkey\&#34;&#34;,&#xA;definition: &#34;\&#34;dinde\&#34;&#34;,&#xA;stressed: &#34;\&#34;t*urkey\&#34;&#34;,&#xA;id: &#34;\&#34;19e12859446591fd25d9720c049a82f9a4f457200724373dfa686d961243bfd1\&#34;&#34;&#xA;},&#xA;&#xA;&#xA;&#xA;{&#xA;term: &#34;\&#34;tale\&#34;&#34;,&#xA;definition: &#34;\&#34;conte\&#34;&#34;,&#xA;stressed: &#34;\&#34;tale\&#34;&#34;,&#xA;id: &#34;\&#34;1aa6e88917c3d4a084b533edb952c2afacab12d5d5a68b9f094df8af0d03fdf8\&#34;&#34;&#xA;},&#xA;&#xA;&#xA;&#xA;{&#xA;term: &#34;\&#34;shelter\&#34;&#34;,&#xA;definition: &#34;\&#34;abri\&#34;&#34;,&#xA;stressed: &#34;\&#34;sh*elter\&#34;&#34;,&#xA;id: &#34;\&#34;45dd9d933199b4e70491f03258caaab1755e84271a7bf95cbf749ea0b1f6e61e\&#34;&#34;&#xA;},&#xA;&#xA;&#xA;&#xA;{&#xA;term: &#34;\&#34;gravitas\&#34;&#34;,&#xA;definition: &#34;\&#34;le sérieux\&#34;&#34;,&#xA;stressed: &#34;\&#34;gr*avitas\&#34;&#34;,&#xA;id: &#34;\&#34;81b59ac135f334fa5e937e00db3c227f6b01fd79dfaa8b81e4986224337e4aa9\&#34;&#34;&#xA;},&#xA;&#xA;&#xA;&#xA;{&#xA;term: &#34;\&#34;foothold\&#34;&#34;,&#xA;definition: &#34;\&#34;poin d&#39;appui\&#34;&#34;,&#xA;stressed: &#34;\&#34;f*o*othold\&#34;&#34;,&#xA;id: &#34;\&#34;bc698576da3822fe3dd8d7b1f187781741aca06a7c81074e6a4939779ad5689a\&#34;&#34;&#xA;},&#xA;&#xA;&#xA;&#xA;{&#xA;term: &#34;\&#34;feast\&#34;&#34;,&#xA;definition: &#34;\&#34;festin\&#34;&#34;,&#xA;stressed: &#34;\&#34;feast\&#34;&#34;,&#xA;id: &#34;\&#34;714fdb41094f951b95d9f1ce1b79bb960ae6d5639b515528b869e0743a1f8415\&#34;&#34;&#xA;},&#xA;&#xA;&#xA;&#xA;{&#xA;term: &#34;\&#34;soil\&#34;&#34;,&#xA;definition: &#34;\&#34;territoire\&#34;&#34;,&#xA;stressed: &#34;\&#34;soil\&#34;&#34;,&#xA;id: &#34;\&#34;b52c817d9f642adb7bc46572afcf0096a65a13b093070af9006f7bff8d6af6c8\&#34;&#34;&#xA;},&#xA;&#xA;&#xA;&#xA;{&#xA;term: &#34;\&#34;inadequate\&#34;&#34;,&#xA;definition: &#34;\&#34;inadéquat(e)\&#34;&#34;,&#xA;stressed: &#34;\&#34;in*adequate\&#34;&#34;,&#xA;id: &#34;\&#34;7e8f1e8b8f97eb95abab233ed0da844770c752f3fbf3b81913f98f14b7b82fa9\&#34;&#34;&#xA;},&#xA;&#xA;&#xA;&#xA;{&#xA;term: &#34;\&#34;(to) argue\&#34;&#34;,&#xA;definition: &#34;\&#34;se disputer\&#34;&#34;,&#xA;stressed: &#34;\&#34;(to) *argue\&#34;&#34;,&#xA;id: &#34;\&#34;6e4380a7bc65f1d0e9c6906859c2b94da5dca41fda611aa53ccfd03ca6170e36\&#34;&#34;&#xA;},&#xA;&#xA;&#xA;&#xA;{&#xA;term: &#34;\&#34;(to) exemplify\&#34;&#34;,&#xA;definition: &#34;\&#34;illustrer\&#34;&#34;,&#xA;stressed: &#34;\&#34;(to) ex*emplify\&#34;&#34;,&#xA;id: &#34;\&#34;26fa94de057d48738fb70737525aac9cdfd8d3cf67d433235be85d9a666d366e\&#34;&#34;&#xA;},&#xA;&#xA;&#xA;&#xA;{&#xA;term: &#34;\&#34;(to) flee\&#34;&#34;,&#xA;definition: &#34;\&#34;fuir\&#34;&#34;,&#xA;stressed: &#34;\&#34;(to) flee\&#34;&#34;,&#xA;id: &#34;\&#34;f3ebd5c4ade271d2b10065676760673e049dafc5a55e6ef4ad8630509d22834c\&#34;&#34;&#xA;},&#xA;&#xA;&#xA;&#xA;{&#xA;term: &#34;\&#34;(to) forgo\&#34;&#34;,&#xA;definition: &#34;\&#34;se passer de\&#34;&#34;,&#xA;stressed: &#34;\&#34;(to) forg*o\&#34;&#34;,&#xA;id: &#34;\&#34;04baf39d840bcf537b33859115266c95d7620d429b53e4ece142a891d68710df\&#34;&#34;&#xA;},&#xA;&#xA;&#xA;].filter(card =&gt; card.term.trim() &amp;&amp; card.definition.trim());&#xA;&#xA;this.setId = &#34;/chapters/america/&#34;.replace(/\/+$/, &#39;&#39;).replace(/^\//, &#39;&#39;);&#xA;this.setTitle = &#34;American Identity&#34;;&#xA;this.cardData = {};&#xA;this.sessionStats = { reviewed: 0 }; &#xA;this.reviewedInSession = new Set();&#xA;this.currentIndex = 0;&#xA;this.isFlipped = false;&#xA;this.studyMode = &#39;term-to-definition&#39;;&#xA;this.viewMode = &#39;browse&#39;; &#xA;this.cardOrder = [...Array(this.flashcards.length).keys()];&#xA;&#xA;this.initDOM();&#xA;this.setupEventListeners();&#xA;&#xA;this.loadProgress().then(() =&gt; {&#xA;this.initializeSession();&#xA;this.updateDisplay();&#xA;});&#xA;}&#xA;&#xA;&#xA;&#xA;&#xA;processStressedText(text) {&#xA;    if (!text) return text;&#xA;    &#xA;    &#xA;    &#xA;    let processed = text.replace(/(\s?)\*([ayeiouwAEYIOUáéíóúÁÉÍÓÚ])/g, &#39;$1&lt;span class=&#34;stressed-vowel&#34;&gt;$2&lt;/span&gt;&#39;);&#xA;    &#xA;    return processed;&#xA;}&#xA;&#xA;&#xA;&#xA;&#xA;initDOM() {&#xA;this.elements = {&#xA;flashcard: document.getElementById(&#39;flashcard&#39;),&#xA;cardQuestion: document.getElementById(&#39;card-question&#39;),&#xA;cardQuestionBack: document.getElementById(&#39;card-question-back&#39;),&#xA;cardAnswer: document.getElementById(&#39;card-answer&#39;),&#xA;currentCard: document.getElementById(&#39;current-card&#39;),&#xA;totalCards: document.getElementById(&#39;total-cards&#39;),&#xA;prevBtn: document.getElementById(&#39;prev-btn&#39;),&#xA;nextBtn: document.getElementById(&#39;next-btn&#39;),&#xA;modeToggleBtn: document.getElementById(&#39;mode-toggle-btn&#39;),&#xA;earlyReviewBtn: document.getElementById(&#39;early-review-btn&#39;),&#xA;resetBtn: document.getElementById(&#39;reset-progress&#39;),&#xA;againBtn: document.getElementById(&#39;again-btn&#39;),&#xA;hardBtn: document.getElementById(&#39;hard-btn&#39;),&#xA;mediumBtn: document.getElementById(&#39;medium-btn&#39;),&#xA;easyBtn: document.getElementById(&#39;easy-btn&#39;),&#xA;reviewedCount: document.getElementById(&#39;reviewed-count&#39;),&#xA;againCount: document.getElementById(&#39;again-count&#39;),&#xA;hardCount: document.getElementById(&#39;hard-count&#39;),&#xA;mediumCount: document.getElementById(&#39;medium-count&#39;),&#xA;easyCount: document.getElementById(&#39;easy-count&#39;),&#xA;reviewCount: document.getElementById(&#39;review-count&#39;),&#xA;completionMessage: document.getElementById(&#39;completion-message&#39;),&#xA;completionText: document.getElementById(&#39;completion-text&#39;),&#xA;earlyReviewOption: document.getElementById(&#39;early-review-option&#39;),&#xA;modeRadios: document.querySelectorAll(&#39;input[name=&#34;study-mode&#34;]&#39;)&#xA;};&#xA;}&#xA;setupEventListeners() {&#xA;this.elements.flashcard.addEventListener(&#39;click&#39;, () =&gt; this.flipCard());&#xA;this.elements.prevBtn.addEventListener(&#39;click&#39;, () =&gt; this.prevCard());&#xA;this.elements.nextBtn.addEventListener(&#39;click&#39;, () =&gt; this.nextCard());&#xA;this.elements.modeToggleBtn.addEventListener(&#39;click&#39;, () =&gt; this.toggleViewMode());&#xA;this.elements.earlyReviewBtn.addEventListener(&#39;click&#39;, () =&gt; this.handleEarlyReview());&#xA;this.elements.resetBtn.addEventListener(&#39;click&#39;, () =&gt; this.resetProgress());&#xA;&#xA;this.elements.againBtn.addEventListener(&#39;click&#39;, () =&gt; this.markDifficulty(&#39;again&#39;));&#xA;this.elements.hardBtn.addEventListener(&#39;click&#39;, () =&gt; this.markDifficulty(&#39;hard&#39;));&#xA;this.elements.mediumBtn.addEventListener(&#39;click&#39;, () =&gt; this.markDifficulty(&#39;medium&#39;));&#xA;this.elements.easyBtn.addEventListener(&#39;click&#39;, () =&gt; this.markDifficulty(&#39;easy&#39;));&#xA;this.elements.modeRadios.forEach(radio =&gt; {&#xA;radio.addEventListener(&#39;change&#39;, (e) =&gt; this.changeStudyMode(e.target.value));&#xA;});&#xA;document.getElementById(&#39;close-completion&#39;).addEventListener(&#39;click&#39;, () =&gt; {&#xA;this.elements.completionMessage.style.display = &#39;none&#39;;&#xA;});&#xA;document.getElementById(&#39;early-review-option&#39;).addEventListener(&#39;click&#39;, () =&gt; {&#xA;this.elements.completionMessage.style.display = &#39;none&#39;;&#xA;this.startEarlyReview();&#xA;});&#xA;document.getElementById(&#39;browse-all-option&#39;).addEventListener(&#39;click&#39;, () =&gt; {&#xA;this.elements.completionMessage.style.display = &#39;none&#39;;&#xA;this.startBrowseMode();&#xA;});&#xA;}&#xA;&#xA;shuffleArray(array) {&#xA;const shuffled = [...array]; &#xA;for (let i = shuffled.length - 1; i &gt; 0; i--) {&#xA;const j = Math.floor(Math.random() * (i + 1));&#xA;[shuffled[i], shuffled[j]] = [shuffled[j], shuffled[i]];&#xA;}&#xA;return shuffled;&#xA;}&#xA;&#xA;getDueCards(includeEarly = false) {&#xA;const now = Date.now();&#xA;const allIndices = [...Array(this.flashcards.length).keys()];&#xA;if (includeEarly) {&#xA;const earlyThreshold = now + (24 * 60 * 60 * 1000);&#xA;return allIndices.filter(idx =&gt; {&#xA;const card = this.cardData[idx];&#xA;return !card || !card.nextReview || card.nextReview &lt;= earlyThreshold;&#xA;});&#xA;} else {&#xA;return allIndices.filter(idx =&gt; {&#xA;const card = this.cardData[idx];&#xA;return !card || !card.nextReview || card.nextReview &lt;= now;&#xA;});&#xA;}&#xA;}&#xA;&#xA;updateCardWithSM2(cardIndex, difficulty) {&#xA;if (!this.cardData[cardIndex]) {&#xA;this.cardData[cardIndex] = {&#xA;interval: 0,&#xA;easeFactor: 2.5,&#xA;reviewCount: 0,&#xA;lastReviewed: Date.now(),&#xA;nextReview: Date.now()&#xA;};&#xA;}&#xA;const card = this.cardData[cardIndex];&#xA;card.reviewCount++;&#xA;card.lastReviewed = Date.now();&#xA;card.lastDifficulty = difficulty; &#xA;let quality;&#xA;switch (difficulty) {&#xA;case &#39;again&#39;: quality = 0; break;&#xA;case &#39;hard&#39;: quality = 2; break;&#xA;case &#39;medium&#39;: quality = 3; break;&#xA;case &#39;easy&#39;: quality = 5; break;&#xA;default: quality = 3;&#xA;}&#xA;&#xA;if (quality &gt;= 3) {&#xA;if (card.reviewCount === 1) {&#xA;card.interval = quality === 5 ? 2 : 1; &#xA;} else if (card.reviewCount === 2) {&#xA;card.interval = 6;&#xA;} else {&#xA;card.interval = Math.round(card.interval * card.easeFactor);&#xA;}&#xA;} else {&#xA;card.interval = quality === 0 ? 0.007 : 1; &#xA;}&#xA;&#xA;if (quality === 0) {&#xA;card.easeFactor = Math.max(1.3, card.easeFactor - 0.2);&#xA;} else if (quality === 2) {&#xA;card.easeFactor = Math.max(1.3, card.easeFactor - 0.15);&#xA;} else if (quality === 3) {&#xA;card.easeFactor = Math.max(1.3, card.easeFactor - 0.02);&#xA;} else if (quality === 5) {&#xA;card.easeFactor = Math.min(2.6, card.easeFactor + 0.1);&#xA;}&#xA;card.nextReview = card.lastReviewed + (card.interval * 24 * 60 * 60 * 1000);&#xA;}&#xA;&#xA;async markDifficulty(level) {&#xA;if (!this.isFlipped) {&#xA;this.flipCard();&#xA;return;&#xA;}&#xA;if (this.viewMode !== &#39;study&#39;) {&#xA;return;&#xA;}&#xA;const cardIndex = this.cardOrder[this.currentIndex];&#xA;&#xA;if (!this.reviewedInSession.has(cardIndex)) {&#xA;this.sessionStats.reviewed++;&#xA;this.reviewedInSession.add(cardIndex);&#xA;}&#xA;&#xA;this.updateCardWithSM2(cardIndex, level);&#xA;&#xA;await this.saveProgress();&#xA;this.updateStatsDisplay();&#xA;&#xA;if (level === &#39;again&#39;) {&#xA;if (this.currentIndex &lt; this.cardOrder.length - 1) {&#xA;this.currentIndex++;&#xA;} else {&#xA;this.currentIndex = 0;&#xA;}&#xA;this.updateCard();&#xA;} else {&#xA;&#xA;this.cardOrder.splice(this.currentIndex, 1);&#xA;if (this.currentIndex &gt;= this.cardOrder.length &amp;&amp; this.cardOrder.length &gt; 0) {&#xA;this.currentIndex = this.cardOrder.length - 1;&#xA;}&#xA;if (this.cardOrder.length &gt; 0) {&#xA;this.updateCard();&#xA;} else {&#xA;this.saveProgress();&#xA;this.showCompletionMessage();&#xA;}&#xA;}&#xA;}&#xA;&#xA;startStudyMode() {&#xA;const dueCards = this.getDueCards();&#xA;if (dueCards.length &gt; 0) {&#xA;this.viewMode = &#39;study&#39;;&#xA;&#xA;this.cardOrder = this.shuffleArray(dueCards);&#xA;this.currentIndex = 0;&#xA;this.updateModeButton(&#39;📚 Studying&#39;, &#39;btn-primary&#39;);&#xA;this.updateCard();&#xA;} else {&#xA;this.checkForEarlyReview();&#xA;}&#xA;}&#xA;startEarlyReview() {&#xA;const allEarly = this.getDueCards(true);&#xA;const dueNow = this.getDueCards(false);&#xA;const earlyOnly = allEarly.filter(idx =&gt; !dueNow.includes(idx));&#xA;if (earlyOnly.length &gt; 0) {&#xA;this.viewMode = &#39;study&#39;;&#xA;&#xA;this.cardOrder = this.shuffleArray(earlyOnly);&#xA;this.currentIndex = 0;&#xA;this.updateModeButton(&#39;📚 Studying&#39;, &#39;btn-primary&#39;);&#xA;this.updateCard();&#xA;} else {&#xA;alert(&#34;No cards are available for early review right now.&#34;);&#xA;}&#xA;}&#xA;startBrowseMode() {&#xA;this.viewMode = &#39;browse&#39;;&#xA;&#xA;this.cardOrder = [...Array(this.flashcards.length).keys()];&#xA;this.currentIndex = 0;&#xA;this.updateModeButton(&#39;📖 Browsing&#39;, &#39;btn-secondary&#39;);&#xA;this.updateCard();&#xA;}&#xA;checkForEarlyReview() {&#xA;const allEarly = this.getDueCards(true);&#xA;const dueNow = this.getDueCards(false);&#xA;const earlyCount = allEarly.length - dueNow.length;&#xA;if (earlyCount &gt; 0) {&#xA;const message = `No cards are due right now, but you have ${earlyCount} card${earlyCount !== 1 ? &#39;s&#39; : &#39;&#39;} due within 24 hours.\n\nWould you like to review them early?`;&#xA;if (confirm(message)) {&#xA;this.startEarlyReview();&#xA;} else {&#xA;this.viewMode = &#39;browse&#39;;&#xA;this.startBrowseMode();&#xA;}&#xA;} else {&#xA;this.showCompletionMessage();&#xA;this.viewMode = &#39;browse&#39;;&#xA;}&#xA;}&#xA;&#xA;updateModeButton(text, className) {&#xA;this.elements.modeToggleBtn.textContent = text;&#xA;this.elements.modeToggleBtn.className = `btn ${className}`;&#xA;&#xA;const difficultyButtons = document.querySelector(&#39;.difficulty-buttons&#39;);&#xA;if (difficultyButtons) {&#xA;if (this.viewMode === &#39;study&#39;) {&#xA;difficultyButtons.style.display = &#39;flex&#39;;&#xA;} else {&#xA;difficultyButtons.style.display = &#39;none&#39;;&#xA;}&#xA;}&#xA;}&#xA;toggleViewMode() {&#xA;if (this.viewMode === &#39;browse&#39;) {&#xA;this.startStudyMode();&#xA;} else {&#xA;this.startBrowseMode();&#xA;}&#xA;&#xA;this.saveProgressSilent();&#xA;}&#xA;handleEarlyReview() {&#xA;const allEarly = this.getDueCards(true);&#xA;const dueNow = this.getDueCards(false);&#xA;const earlyCount = allEarly.length - dueNow.length;&#xA;if (earlyCount &gt; 0) {&#xA;this.startEarlyReview();&#xA;} else if (dueNow.length &gt; 0) {&#xA;alert(&#34;You have cards due for review! Use the Study button instead.&#34;);&#xA;} else {&#xA;alert(&#34;No cards are available for early review right now.&#34;);&#xA;}&#xA;}&#xA;&#xA;updateCard() {&#xA;if (this.flashcards.length === 0) {&#xA;this.elements.cardQuestion.innerHTML = &#34;No flashcards available&#34;;&#xA;this.elements.cardQuestionBack.innerHTML = &#34;No flashcards available&#34;;&#xA;this.elements.cardAnswer.innerHTML = &#34;Please add lexicon data to the front matter&#34;;&#xA;return;&#xA;}&#xA;if (this.currentIndex &lt; 0 || this.currentIndex &gt;= this.cardOrder.length) {&#xA;this.currentIndex = 0;&#xA;}&#xA;const cardIndex = this.cardOrder[this.currentIndex];&#xA;const card = this.flashcards[cardIndex];&#xA;if (!card) {&#xA;console.error(&#39;Invalid card at index:&#39;, cardIndex);&#xA;return;&#xA;}&#xA;let question, answer;&#xA;if (this.studyMode === &#39;term-to-definition&#39;) {&#xA;&#xA;question = card.stressed || card.term;&#xA;answer = card.definition;&#xA;} else {&#xA;question = card.definition;&#xA;&#xA;answer = card.stressed || card.term;&#xA;}&#xA;&#xA;this.elements.cardQuestion.innerHTML = this.processStressedText(question);&#xA;this.elements.cardQuestionBack.innerHTML = this.processStressedText(question);&#xA;this.elements.cardAnswer.innerHTML = this.processStressedText(answer);&#xA;this.elements.currentCard.textContent = this.currentIndex + 1;&#xA;this.elements.totalCards.textContent = this.cardOrder.length;&#xA;&#xA;this.elements.prevBtn.disabled = this.currentIndex === 0;&#xA;this.elements.nextBtn.disabled = this.currentIndex === this.cardOrder.length - 1;&#xA;&#xA;this.isFlipped = false;&#xA;this.elements.flashcard.classList.remove(&#39;flipped&#39;);&#xA;}&#xA;&#xA;updateStatsDisplay() {&#xA;const totalReviewed = Object.values(this.cardData).filter(card =&gt; card &amp;&amp; card.reviewCount &gt; 0).length;&#xA;const needsReview = this.getDueCards().length;&#xA;&#xA;const difficultyStats = { again: 0, hard: 0, medium: 0, easy: 0 };&#xA;for (let i = 0; i &lt; this.flashcards.length; i++) {&#xA;const card = this.cardData[i];&#xA;if (card &amp;&amp; card.lastDifficulty) {&#xA;difficultyStats[card.lastDifficulty]++;&#xA;}&#xA;}&#xA;this.elements.reviewedCount.textContent = totalReviewed;&#xA;this.elements.reviewCount.textContent = needsReview;&#xA;&#xA;if (this.elements.againCount) this.elements.againCount.textContent = difficultyStats.again;&#xA;if (this.elements.hardCount) this.elements.hardCount.textContent = difficultyStats.hard;&#xA;if (this.elements.mediumCount) this.elements.mediumCount.textContent = difficultyStats.medium;&#xA;this.elements.easyCount.textContent = difficultyStats.easy;&#xA;}&#xA;updateDisplay() {&#xA;this.updateCard();&#xA;this.updateStatsDisplay();&#xA;&#xA;const radio = document.querySelector(`input[value=&#34;${this.studyMode}&#34;]`);&#xA;if (radio) radio.checked = true;&#xA;&#xA;if (this.viewMode === &#39;study&#39;) {&#xA;this.updateModeButton(&#39;📚 Studying&#39;, &#39;btn-primary&#39;);&#xA;} else {&#xA;this.updateModeButton(&#39;📖 Browsing&#39;, &#39;btn-secondary&#39;);&#xA;}&#xA;}&#xA;&#xA;flipCard() {&#xA;this.isFlipped = !this.isFlipped;&#xA;this.elements.flashcard.classList.toggle(&#39;flipped&#39;);&#xA;}&#xA;nextCard() {&#xA;if (this.currentIndex &lt; this.cardOrder.length - 1) {&#xA;this.currentIndex++;&#xA;this.updateCard();&#xA;&#xA;if (this.viewMode === &#39;study&#39;) {&#xA;this.saveProgressSilent();&#xA;}&#xA;}&#xA;}&#xA;prevCard() {&#xA;if (this.currentIndex &gt; 0) {&#xA;this.currentIndex--;&#xA;this.updateCard();&#xA;&#xA;if (this.viewMode === &#39;study&#39;) {&#xA;this.saveProgressSilent();&#xA;}&#xA;}&#xA;}&#xA;changeStudyMode(mode) {&#xA;this.studyMode = mode;&#xA;this.updateCard();&#xA;&#xA;this.saveProgressSilent();&#xA;}&#xA;&#xA;showCompletionMessage() {&#xA;this.viewMode = &#39;browse&#39;;&#xA;this.updateModeButton(&#39;📖 Browsing&#39;, &#39;btn-secondary&#39;);&#xA;const nextReview = this.getNextReviewTime();&#xA;const allEarly = this.getDueCards(true);&#xA;const dueNow = this.getDueCards(false);&#xA;const earlyCards = allEarly.length - dueNow.length;&#xA;let message = &#34;You&#39;ve reviewed all due cards!&#34;;&#xA;if (nextReview) {&#xA;const timeUntil = nextReview - Date.now();&#xA;const hoursUntil = Math.ceil(timeUntil / (1000 * 60 * 60));&#xA;const daysUntil = Math.ceil(timeUntil / (1000 * 60 * 60 * 24));&#xA;if (hoursUntil &lt; 24) {&#xA;message += ` Next cards will be ready in about ${hoursUntil} hour${hoursUntil !== 1 ? &#39;s&#39; : &#39;&#39;}.`;&#xA;} else {&#xA;message += ` Next cards will be ready in about ${daysUntil} day${daysUntil !== 1 ? &#39;s&#39; : &#39;&#39;}.`;&#xA;}&#xA;}&#xA;this.elements.completionText.textContent = message;&#xA;if (earlyCards &gt; 0) {&#xA;this.elements.earlyReviewOption.style.display = &#39;inline-block&#39;;&#xA;this.elements.earlyReviewOption.textContent = `⏰ Review ${earlyCards} Early Card${earlyCards !== 1 ? &#39;s&#39; : &#39;&#39;}`;&#xA;} else {&#xA;this.elements.earlyReviewOption.style.display = &#39;none&#39;;&#xA;}&#xA;this.elements.completionMessage.style.display = &#39;flex&#39;;&#xA;this.saveProgressSilent();&#xA;}&#xA;getNextReviewTime() {&#xA;const now = Date.now();&#xA;let earliest = null;&#xA;for (let i = 0; i &lt; this.flashcards.length; i++) {&#xA;const card = this.cardData[i];&#xA;if (card &amp;&amp; card.nextReview &amp;&amp; card.nextReview &gt; now) {&#xA;if (!earliest || card.nextReview &lt; earliest) {&#xA;earliest = card.nextReview;&#xA;}&#xA;}&#xA;}&#xA;return earliest;&#xA;}&#xA;&#xA;resetProgress() {&#xA;this.cardData = {};&#xA;this.sessionStats = { reviewed: 0 };&#xA;this.reviewedInSession = new Set();&#xA;this.viewMode = &#39;browse&#39;;&#xA;this.cardOrder = [...Array(this.flashcards.length).keys()];&#xA;this.currentIndex = 0;&#xA;this.updateDisplay();&#xA;this.saveProgressSilent();&#xA;}&#xA;&#xA;initializeSession() {&#xA;if (this.viewMode === &#39;study&#39;) {&#xA;const dueCards = this.getDueCards();&#xA;if (dueCards.length &gt; 0) {&#xA;&#xA;this.cardOrder = this.shuffleArray(dueCards);&#xA;this.currentIndex = 0;&#xA;this.updateModeButton(&#39;📚 Studying&#39;, &#39;btn-primary&#39;);&#xA;} else {&#xA;this.viewMode = &#39;browse&#39;;&#xA;this.cardOrder = [...Array(this.flashcards.length).keys()];&#xA;this.currentIndex = Math.min(this.currentIndex, this.cardOrder.length - 1);&#xA;this.updateModeButton(&#39;📖 Browsing&#39;, &#39;btn-secondary&#39;);&#xA;}&#xA;} else {&#xA;&#xA;this.cardOrder = [...Array(this.flashcards.length).keys()];&#xA;this.currentIndex = Math.min(this.currentIndex, this.cardOrder.length - 1);&#xA;this.updateModeButton(&#39;📖 Browsing&#39;, &#39;btn-secondary&#39;);&#xA;}&#xA;}&#xA;&#xA;async saveProgress() {&#xA;this.saveToLocalStorage();&#xA;try {&#xA;const { data: { session }, error } = await supabaseClient.auth.getSession();&#xA;if (error || !session?.user?.id) {&#xA;return;&#xA;}&#xA;const progressData = {&#xA;user_id: session.user.id,&#xA;set_id: this.setId,&#xA;set_title: this.setTitle,&#xA;card_data: {&#xA;cardOrder: this.cardOrder,&#xA;currentIndex: this.currentIndex,&#xA;studyMode: this.studyMode,&#xA;viewMode: this.viewMode,&#xA;cardData: this.cardData&#xA;},&#xA;stats: this.sessionStats,&#xA;updated_at: new Date().toISOString()&#xA;};&#xA;const { error: saveError } = await supabaseClient&#xA;.from(&#39;flashcard_progress&#39;)&#xA;.upsert(progressData, { onConflict: &#39;user_id,set_id&#39; });&#xA;if (saveError) {&#xA;console.error(&#39;Supabase save error:&#39;, saveError);&#xA;}&#xA;} catch (e) {&#xA;console.error(&#39;Error saving progress:&#39;, e);&#xA;}&#xA;}&#xA;&#xA;async saveProgressSilent() {&#xA;this.saveToLocalStorage();&#xA;try {&#xA;const { data: { session }, error } = await supabaseClient.auth.getSession();&#xA;if (error || !session?.user?.id) {&#xA;return;&#xA;}&#xA;const progressData = {&#xA;user_id: session.user.id,&#xA;set_id: this.setId,&#xA;set_title: this.setTitle,&#xA;card_data: {&#xA;cardOrder: this.cardOrder,&#xA;currentIndex: this.currentIndex,&#xA;studyMode: this.studyMode,&#xA;viewMode: this.viewMode,&#xA;cardData: this.cardData&#xA;},&#xA;stats: this.sessionStats,&#xA;updated_at: new Date().toISOString()&#xA;};&#xA;await supabaseClient&#xA;.from(&#39;flashcard_progress&#39;)&#xA;.upsert(progressData, { onConflict: &#39;user_id,set_id&#39; });&#xA;} catch (e) {&#xA;console.error(&#39;Error saving progress silently:&#39;, e);&#xA;}&#xA;}&#xA;async loadProgress() {&#xA;&#xA;this.cardData = {};&#xA;this.sessionStats = { reviewed: 0 };&#xA;this.reviewedInSession = new Set();&#xA;try {&#xA;const { data: { session }, error } = await supabaseClient.auth.getSession();&#xA;if (error || !session?.user?.id) {&#xA;this.loadFromLocalStorage();&#xA;return;&#xA;}&#xA;const { data, error: dbError } = await supabaseClient&#xA;.from(&#39;flashcard_progress&#39;)&#xA;.select(&#39;*&#39;)&#xA;.eq(&#39;user_id&#39;, session.user.id)&#xA;.eq(&#39;set_id&#39;, this.setId)&#xA;.single();&#xA;if (dbError &amp;&amp; dbError.code !== &#39;PGRST116&#39;) {&#xA;console.error(&#39;Database error:&#39;, dbError);&#xA;this.loadFromLocalStorage();&#xA;return;&#xA;}&#xA;if (data) {&#xA;this.loadFromData(data);&#xA;&#xA;await this.migrateLocalStorageIfNewer(data.updated_at);&#xA;} else {&#xA;this.loadFromLocalStorage();&#xA;if (session?.user) {&#xA;await this.saveProgressSilent();&#xA;}&#xA;}&#xA;} catch (e) {&#xA;console.error(&#39;Error loading progress:&#39;, e);&#xA;this.loadFromLocalStorage();&#xA;}&#xA;}&#xA;&#xA;loadFromData(data) {&#xA;if (data.card_data) {&#xA;this.cardOrder = this.validateArray(data.card_data.cardOrder, this.flashcards.length) ||&#xA;[...Array(this.flashcards.length).keys()];&#xA;this.cardData = this.validateCardData(data.card_data.cardData) || {};&#xA;this.currentIndex = Math.max(0, Math.min(data.card_data.currentIndex || 0, this.cardOrder.length - 1));&#xA;this.studyMode = [&#39;term-to-definition&#39;, &#39;definition-to-term&#39;].includes(data.card_data.studyMode) ?&#xA;data.card_data.studyMode : &#39;term-to-definition&#39;;&#xA;this.viewMode = [&#39;browse&#39;, &#39;study&#39;].includes(data.card_data.viewMode) ?&#xA;data.card_data.viewMode : &#39;browse&#39;;&#xA;}&#xA;if (data.stats &amp;&amp; typeof data.stats === &#39;object&#39;) {&#xA;this.sessionStats = {&#xA;reviewed: data.stats.reviewed || 0&#xA;};&#xA;}&#xA;}&#xA;loadFromLocalStorage() {&#xA;const storageKey = `flashcards_${this.setId}`;&#xA;const saved = localStorage.getItem(storageKey);&#xA;if (saved) {&#xA;try {&#xA;const data = JSON.parse(saved);&#xA;this.loadFromData({&#xA;card_data: {&#xA;cardOrder: data.cardOrder,&#xA;cardData: data.cardData,&#xA;currentIndex: data.currentIndex,&#xA;studyMode: data.studyMode,&#xA;viewMode: data.viewMode&#xA;},&#xA;stats: data.sessionStats&#xA;});&#xA;} catch (e) {&#xA;console.error(&#39;Error parsing localStorage:&#39;, e);&#xA;}&#xA;}&#xA;}&#xA;async migrateLocalStorageIfNewer(dbUpdatedAt) {&#xA;const storageKey = `flashcards_${this.setId}`;&#xA;const saved = localStorage.getItem(storageKey);&#xA;if (!saved) return;&#xA;try {&#xA;const localData = JSON.parse(saved);&#xA;const localUpdated = new Date(localData.lastUpdated || 0);&#xA;const dbUpdated = new Date(dbUpdatedAt);&#xA;if (localUpdated &gt; dbUpdated) {&#xA;this.loadFromData({&#xA;card_data: {&#xA;cardOrder: localData.cardOrder,&#xA;cardData: localData.cardData,&#xA;currentIndex: localData.currentIndex,&#xA;studyMode: localData.studyMode,&#xA;viewMode: localData.viewMode&#xA;},&#xA;stats: localData.sessionStats&#xA;});&#xA;await this.saveProgressSilent();&#xA;}&#xA;} catch (e) {&#xA;console.error(&#39;Error during migration:&#39;, e);&#xA;}&#xA;}&#xA;saveToLocalStorage() {&#xA;const storageKey = `flashcards_${this.setId}`;&#xA;const data = {&#xA;cardOrder: this.cardOrder,&#xA;currentIndex: this.currentIndex,&#xA;studyMode: this.studyMode,&#xA;viewMode: this.viewMode,&#xA;cardData: this.cardData,&#xA;sessionStats: this.sessionStats,&#xA;lastUpdated: new Date().toISOString(),&#xA;setTitle: this.setTitle&#xA;};&#xA;try {&#xA;localStorage.setItem(storageKey, JSON.stringify(data));&#xA;} catch (e) {&#xA;console.error(&#39;Error saving to localStorage:&#39;, e);&#xA;}&#xA;}&#xA;&#xA;validateArray(arr, expectedLength) {&#xA;if (!Array.isArray(arr) || arr.length !== expectedLength) return null;&#xA;return arr.every(idx =&gt; Number.isInteger(idx) &amp;&amp; idx &gt;= 0 &amp;&amp; idx &lt; expectedLength) ? arr : null;&#xA;}&#xA;validateCardData(data) {&#xA;if (!data || typeof data !== &#39;object&#39;) return null;&#xA;const validated = {};&#xA;for (const [key, value] of Object.entries(data)) {&#xA;if (value &amp;&amp; typeof value === &#39;object&#39; &amp;&amp;&#xA;typeof value.interval === &#39;number&#39; &amp;&amp;&#xA;typeof value.easeFactor === &#39;number&#39;) {&#xA;validated[key] = value;&#xA;}&#xA;}&#xA;return validated;&#xA;}&#xA;}&#xA;&#xA;document.addEventListener(&#39;DOMContentLoaded&#39;, () =&gt; {&#xA;updateAuthLink();&#xA;window.flashcardSystem = new FlashcardSystem();&#xA;});&#xA;&#xA;supabaseClient.auth.onAuthStateChange(async (event, session) =&gt; {&#xA;console.log(&#39;Auth state changed:&#39;, event);&#xA;updateAuthLink();&#xA;&#xA;});&#xA;&#xA;window.addEventListener(&#39;focus&#39;, () =&gt; {&#xA;setTimeout(updateAuthLink, 1000); &#xA;});&#xA;&lt;/script&gt;</description>
      
    </item>
    
    <item>
      <title>Flashcards</title>
      <link>https://premieres.stephanejacquet.fr/chapters/power_of_english/flashcards/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      
      <guid>https://premieres.stephanejacquet.fr/chapters/power_of_english/flashcards/</guid>
      <description>&lt;div class=&#34;flashcards-container&#34;&gt;&#xA;&lt;div style=&#34;display:flex; justify-content:space-between; align-items:baseline; gap:1rem; flex-wrap:wrap;&#34;&gt;&#xA;&lt;h2&gt;🧠 The Magic of English &amp;mdash; Flashcards&lt;/h2&gt;&#xA;&lt;a href=&#34;https://premieres.stephanejacquet.fr/login/&#34; id=&#34;auth-link&#34; class=&#34;login-link&#34; style=&#34;color:#007bff; text-decoration:none; font-size:0.9rem; white-space:nowrap;&#34;&gt;Login&lt;/a&gt;&#xA;&lt;/div&gt;&#xA;&lt;div class=&#34;flashcards-header&#34;&gt;&#xA;&lt;div class=&#34;flashcards-controls&#34;&gt;&#xA;&lt;div class=&#34;mode-selector&#34;&gt;&#xA;&lt;label class=&#34;mode-option&#34;&gt;&#xA;&lt;input type=&#34;radio&#34; name=&#34;study-mode&#34; value=&#34;term-to-definition&#34; checked&gt;&#xA;&lt;span&gt;Term → Definition&lt;/span&gt;&#xA;&lt;/label&gt;&#xA;&lt;label class=&#34;mode-option&#34;&gt;&#xA;&lt;input type=&#34;radio&#34; name=&#34;study-mode&#34; value=&#34;definition-to-term&#34;&gt;&#xA;&lt;span&gt;Definition → Term&lt;/span&gt;&#xA;&lt;/label&gt;&#xA;&lt;/div&gt;&#xA;&lt;div class=&#34;control-buttons&#34;&gt;&#xA;&lt;button id=&#34;mode-toggle-btn&#34; class=&#34;btn btn-secondary&#34;&gt;📖 Browse&lt;/button&gt;&#xA;&lt;button id=&#34;early-review-btn&#34; class=&#34;btn btn-info&#34;&gt;⏰ Early Review&lt;/button&gt;&#xA;&lt;button id=&#34;reset-progress&#34; class=&#34;btn btn-outline&#34;&gt;🔄 Reset&lt;/button&gt;&#xA;&lt;/div&gt;&#xA;&lt;div class=&#34;progress-display&#34;&gt;&#xA;&lt;span id=&#34;current-card&#34;&gt;1&lt;/span&gt; / &lt;span id=&#34;total-cards&#34;&gt;9&lt;/span&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&#xA;&lt;div class=&#34;flashcard-wrapper&#34;&gt;&#xA;&lt;div class=&#34;flashcard&#34; id=&#34;flashcard&#34;&gt;&#xA;&lt;div class=&#34;flashcard-inner&#34;&gt;&#xA;&lt;div class=&#34;flashcard-front&#34;&gt;&#xA;&lt;div class=&#34;card-content&#34;&gt;&#xA;&lt;div class=&#34;question&#34; id=&#34;card-question&#34;&gt;&lt;/div&gt;&#xA;&lt;div class=&#34;card-hint&#34;&gt;Tap to reveal answer&lt;/div&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&#xA;&lt;div class=&#34;flashcard-back&#34;&gt;&#xA;&lt;div class=&#34;card-content&#34;&gt;&#xA;&lt;div class=&#34;question-small&#34; id=&#34;card-question-back&#34;&gt;&lt;/div&gt;&#xA;&lt;div class=&#34;answer&#34; id=&#34;card-answer&#34;&gt;&lt;/div&gt;&#xA;&lt;div class=&#34;card-hint&#34;&gt;Tap to flip back&lt;/div&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&#xA;&lt;div class=&#34;flashcards-navigation&#34;&gt;&#xA;&lt;div class=&#34;nav-top&#34;&gt;&#xA;&lt;button id=&#34;next-btn&#34; class=&#34;btn btn-primary&#34;&gt;Next →&lt;/button&gt;&#xA;&lt;/div&gt;&#xA;&lt;div class=&#34;nav-middle&#34;&gt;&#xA;&lt;div class=&#34;difficulty-buttons&#34;&gt;&#xA;&lt;button id=&#34;again-btn&#34; class=&#34;btn btn-danger-dark&#34;&gt;🚫 Again&lt;/button&gt;&#xA;&lt;button id=&#34;hard-btn&#34; class=&#34;btn btn-danger&#34;&gt;😰 Hard&lt;/button&gt;&#xA;&lt;button id=&#34;medium-btn&#34; class=&#34;btn btn-warning&#34;&gt;🤔 Medium&lt;/button&gt;&#xA;&lt;button id=&#34;easy-btn&#34; class=&#34;btn btn-success&#34;&gt;😊 Easy&lt;/button&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&#xA;&lt;div class=&#34;nav-bottom&#34;&gt;&#xA;&lt;button id=&#34;prev-btn&#34; class=&#34;btn btn-primary&#34;&gt;← Previous&lt;/button&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&#xA;&lt;div class=&#34;progress-stats&#34;&gt;&#xA;&lt;div class=&#34;stat&#34;&gt;&#xA;&lt;span class=&#34;stat-label&#34;&gt;Reviewed:&lt;/span&gt;&#xA;&lt;span id=&#34;reviewed-count&#34;&gt;0&lt;/span&gt;&#xA;&lt;/div&gt;&#xA;&lt;div class=&#34;stat&#34;&gt;&#xA;&lt;span class=&#34;stat-label&#34;&gt;Again:&lt;/span&gt;&#xA;&lt;span id=&#34;again-count&#34;&gt;0&lt;/span&gt;&#xA;&lt;/div&gt;&#xA;&lt;div class=&#34;stat&#34;&gt;&#xA;&lt;span class=&#34;stat-label&#34;&gt;Hard:&lt;/span&gt;&#xA;&lt;span id=&#34;hard-count&#34;&gt;0&lt;/span&gt;&#xA;&lt;/div&gt;&#xA;&lt;div class=&#34;stat&#34;&gt;&#xA;&lt;span class=&#34;stat-label&#34;&gt;Medium:&lt;/span&gt;&#xA;&lt;span id=&#34;medium-count&#34;&gt;0&lt;/span&gt;&#xA;&lt;/div&gt;&#xA;&lt;div class=&#34;stat&#34;&gt;&#xA;&lt;span class=&#34;stat-label&#34;&gt;Easy:&lt;/span&gt;&#xA;&lt;span id=&#34;easy-count&#34;&gt;0&lt;/span&gt;&#xA;&lt;/div&gt;&#xA;&lt;div class=&#34;stat&#34;&gt;&#xA;&lt;span class=&#34;stat-label&#34;&gt;Due:&lt;/span&gt;&#xA;&lt;span id=&#34;review-count&#34;&gt;0&lt;/span&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&#xA;&lt;div class=&#34;completion-message&#34; id=&#34;completion-message&#34; style=&#34;display: none;&#34;&gt;&#xA;&lt;div class=&#34;completion-content&#34;&gt;&#xA;&lt;div class=&#34;completion-icon&#34;&gt;🎉&lt;/div&gt;&#xA;&lt;h3 class=&#34;completion-title&#34;&gt;Great Job!&lt;/h3&gt;&#xA;&lt;p class=&#34;completion-text&#34; id=&#34;completion-text&#34;&gt;&lt;/p&gt;&#xA;&lt;div class=&#34;completion-actions&#34;&gt;&#xA;&lt;button id=&#34;early-review-option&#34; class=&#34;btn btn-info&#34; style=&#34;display: none;&#34;&gt;⏰ Review Early Cards&lt;/button&gt;&#xA;&lt;button id=&#34;browse-all-option&#34; class=&#34;btn btn-secondary&#34;&gt;📖 Browse All Cards&lt;/button&gt;&#xA;&lt;button id=&#34;close-completion&#34; class=&#34;btn btn-primary&#34;&gt;✨ Done&lt;/button&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&#xA;&lt;style&gt;&#xA; &#xA;.stressed-vowel {&#xA;color: red !important;&#xA;font-weight: bold;&#xA;}&#xA; &#xA;.btn-danger-dark {&#xA;background: #8b0000;&#xA;color: white;&#xA;}&#xA;.btn-danger-dark:hover {&#xA;background: #a00000;&#xA;transform: translateY(-1px);&#xA;box-shadow: 0 2px 8px rgba(0,0,0,0.2);&#xA;}&#xA; &#xA;.flashcards-container {&#xA;max-width: 600px;&#xA;margin: 0 auto;&#xA;padding: 1rem;&#xA;font-family: -apple-system, BlinkMacSystemFont, &#39;Segoe UI&#39;, Roboto, sans-serif;&#xA;display: flex;&#xA;flex-direction: column;&#xA;box-sizing: border-box;&#xA;gap: 1rem;&#xA;}&#xA;.flashcards-header {&#xA;display: flex;&#xA;justify-content: space-between;&#xA;align-items: center;&#xA;margin-bottom: 1rem;&#xA;flex-wrap: wrap;&#xA;gap: 1rem;&#xA;}&#xA;.flashcards-header h3 {&#xA;margin: 0;&#xA;color: inherit;&#xA;font-size: clamp(1.2rem, 4vw, 1.5rem);&#xA;}&#xA;.flashcards-controls {&#xA;display: flex;&#xA;align-items: center;&#xA;gap: 1.2rem;&#xA;flex-wrap: wrap;&#xA;padding: 0.5rem 0;&#xA;}&#xA;.mode-selector {&#xA;display: flex;&#xA;gap: 0.8rem;&#xA;align-items: center;&#xA;}&#xA;.mode-option {&#xA;display: flex;&#xA;align-items: center;&#xA;gap: 0.5rem;&#xA;cursor: pointer;&#xA;padding: 0.5rem 0.75rem;&#xA;border-radius: 20px;&#xA;background: #f8f9fa;&#xA;border: 1px solid #ced4da;&#xA;color: #212529;&#xA;transition: all 0.2s ease;&#xA;font-size: clamp(0.75rem, 3vw, 0.9rem);&#xA;white-space: nowrap;&#xA;}&#xA;.mode-option span {&#xA;color: #212529;&#xA;}&#xA;.mode-option:hover {&#xA;background: #e9ecef;&#xA;}&#xA;.mode-option input[type=&#34;radio&#34;] {&#xA;margin: 0;&#xA;}&#xA;.mode-option input[type=&#34;radio&#34;]:checked + span {&#xA;font-weight: bold;&#xA;color: #007bff;&#xA;}&#xA;.control-buttons {&#xA;display: flex;&#xA;gap: 0.8rem;&#xA;}&#xA;.progress-display {&#xA;background: #f5f5f5;&#xA;padding: 0.5rem 0.75rem;&#xA;border-radius: 20px;&#xA;border: 1px solid #ced4da;&#xA;font-weight: bold;&#xA;color: #212529;&#xA;font-size: clamp(0.8rem, 3vw, 0.9rem);&#xA;}&#xA;.flashcard-wrapper {&#xA;perspective: 1000px;&#xA;margin: 1.5rem 0;&#xA;display: flex;&#xA;align-items: center;&#xA;}&#xA;.flashcard {&#xA;width: 100%;&#xA;height: clamp(220px, 35vh, 320px);&#xA;position: relative;&#xA;cursor: pointer;&#xA;transition: transform 0.3s ease;&#xA;}&#xA;.flashcard:hover {&#xA;transform: translateY(-2px);&#xA;}&#xA;.flashcard-inner {&#xA;position: relative;&#xA;width: 100%;&#xA;height: 100%;&#xA;text-align: center;&#xA;transition: transform 0.6s;&#xA;transform-style: preserve-3d;&#xA;}&#xA;.flashcard.flipped .flashcard-inner {&#xA;transform: rotateY(180deg);&#xA;}&#xA;.flashcard-front, .flashcard-back {&#xA;position: absolute;&#xA;width: 100%;&#xA;height: 100%;&#xA;backface-visibility: hidden;&#xA;border-radius: 15px;&#xA;box-shadow: 0 4px 20px rgba(0,0,0,0.1);&#xA;display: flex;&#xA;align-items: center;&#xA;justify-content: center;&#xA;}&#xA;.flashcard-front {&#xA;background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);&#xA;color: white;&#xA;}&#xA;.flashcard-back {&#xA;background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);&#xA;color: white;&#xA;transform: rotateY(180deg);&#xA;}&#xA;.card-content {&#xA;padding: clamp(1.5rem, 5vw, 2.5rem);&#xA;width: 100%;&#xA;height: 100%;&#xA;display: flex;&#xA;flex-direction: column;&#xA;justify-content: center;&#xA;box-sizing: border-box;&#xA;overflow: hidden;&#xA;}&#xA;&#xA; &#xA;.term, .question {&#xA;    font-size: clamp(1.4rem, 5vw, 2rem);&#xA;    font-weight: bold;&#xA;    margin-bottom: 1rem;&#xA;    text-shadow: 0 2px 4px rgba(0,0,0,0.3);&#xA;    line-height: 1.3;&#xA;    overflow-wrap: break-word;&#xA;    hyphens: auto;&#xA;    display: flex;&#xA;    align-items: center;&#xA;    justify-content: center;&#xA;    text-align: center;&#xA;    height: 100%;&#xA;    margin: 0 auto;&#xA;     &#xA;    white-space: pre-wrap;&#xA;}&#xA;&#xA;&#xA;&#xA;&#xA;&#xA;&#xA;&#xA;.term-small, .question-small {&#xA;font-size: clamp(0.85rem, 3.2vw, 1.1rem);&#xA;font-weight: bold;&#xA;margin-bottom: 0.75rem;&#xA;opacity: 0.8;&#xA;line-height: 1.3;&#xA;overflow-wrap: break-word;&#xA;text-align: center;&#xA;}&#xA;.definition, .answer {&#xA;font-size: clamp(1.4rem, 5vw, 2rem);&#xA;font-weight: bold;&#xA;margin-bottom: 1rem;&#xA;text-shadow: 0 2px 4px rgba(0,0,0,0.3);&#xA;line-height: 1.3;&#xA;overflow-wrap: break-word;&#xA;hyphens: auto;&#xA;flex: 1;&#xA;display: flex;&#xA;align-items: center;&#xA;justify-content: center;&#xA;text-align: center;&#xA;}&#xA;.card-hint {&#xA;font-size: clamp(0.7rem, 2.3vw, 0.85rem);&#xA;opacity: 0.7;&#xA;font-style: italic;&#xA;margin-top: auto;&#xA;text-align: center;&#xA;}&#xA;.flashcards-navigation {&#xA;display: flex;&#xA;flex-direction: column;&#xA;gap: 0.75rem;&#xA;margin: 1.5rem 0;&#xA;}&#xA;.nav-top, .nav-bottom {&#xA;display: flex;&#xA;justify-content: center;&#xA;}&#xA;.nav-middle {&#xA;display: flex;&#xA;justify-content: center;&#xA;}&#xA;.difficulty-buttons {&#xA;display: flex;&#xA;gap: 0.8rem;&#xA;justify-content: center;&#xA;flex-wrap: wrap;&#xA;}&#xA;.btn {&#xA;padding: clamp(0.4rem, 1.8vw, 0.6rem) clamp(0.8rem, 2.5vw, 1rem);&#xA;border: none;&#xA;border-radius: 8px;&#xA;cursor: pointer;&#xA;font-weight: 500;&#xA;transition: all 0.2s ease;&#xA;font-size: clamp(0.75rem, 2.8vw, 0.85rem);&#xA;white-space: nowrap;&#xA;min-width: fit-content;&#xA;}&#xA;.btn:hover {&#xA;transform: translateY(-1px);&#xA;box-shadow: 0 2px 8px rgba(0,0,0,0.2);&#xA;}&#xA;.btn-primary { background: #007bff; color: white; }&#xA;.btn-secondary { background: #6c757d; color: white; }&#xA;.btn-secondary:hover { background: #5a6268; }&#xA;.btn-success { background: #28a745; color: white; }&#xA;.btn-warning { background: #ffc107; color: #212529; }&#xA;.btn-danger { background: #dc3545; color: white; }&#xA;.btn-outline { background: white; border: 2px solid #495057; color: #212529; }&#xA;.btn-outline:hover { background: #495057; color: white; }&#xA;.btn-info { background: #17a2b8; color: white; }&#xA;.btn-info:hover { background: #138496; }&#xA;.btn:disabled {&#xA;opacity: 0.5;&#xA;cursor: not-allowed;&#xA;transform: none;&#xA;}&#xA;.progress-stats {&#xA;display: grid;&#xA;grid-template-columns: repeat(auto-fit, minmax(70px, 1fr));&#xA;gap: 0.75rem;&#xA;background: #f8f9fa;&#xA;border: 1px solid #ced4da;&#xA;padding: 0.75rem;&#xA;border-radius: 10px;&#xA;margin-top: 1rem;&#xA;}&#xA;.stat {&#xA;text-align: center;&#xA;flex: 1;&#xA;min-width: 70px;&#xA;}&#xA;.stat-label {&#xA;display: block;&#xA;font-size: clamp(0.65rem, 2.3vw, 0.75rem);&#xA;color: #666;&#xA;text-transform: uppercase;&#xA;letter-spacing: 0.5px;&#xA;}&#xA;.stat span:last-child {&#xA;display: block;&#xA;font-size: clamp(1rem, 3.5vw, 1.3rem);&#xA;font-weight: bold;&#xA;color: #333;&#xA;margin-top: 0.25rem;&#xA;}&#xA;.completion-message {&#xA;position: fixed;&#xA;top: 0;&#xA;left: 0;&#xA;width: 100%;&#xA;height: 100%;&#xA;background: rgba(0, 0, 0, 0.8);&#xA;display: flex;&#xA;align-items: center;&#xA;justify-content: center;&#xA;z-index: 1000;&#xA;backdrop-filter: blur(5px);&#xA;}&#xA;.completion-content {&#xA;background: white;&#xA;padding: 2rem;&#xA;border-radius: 20px;&#xA;text-align: center;&#xA;max-width: 90%;&#xA;max-height: 90%;&#xA;overflow-y: auto;&#xA;box-shadow: 0 20px 40px rgba(0, 0, 0, 0.3);&#xA;animation: completionSlideIn 0.3s ease-out;&#xA;}&#xA;@keyframes completionSlideIn {&#xA;from {&#xA;opacity: 0;&#xA;transform: translateY(-50px) scale(0.9);&#xA;}&#xA;to {&#xA;opacity: 1;&#xA;transform: translateY(0) scale(1);&#xA;}&#xA;}&#xA;.completion-icon {&#xA;font-size: 4rem;&#xA;margin-bottom: 1rem;&#xA;animation: bounce 1s ease-in-out infinite alternate;&#xA;}&#xA;@keyframes bounce {&#xA;from { transform: translateY(0); }&#xA;to { transform: translateY(-10px); }&#xA;}&#xA;.completion-title {&#xA;color: #333;&#xA;margin-bottom: 1rem;&#xA;font-size: 2rem;&#xA;font-weight: bold;&#xA;}&#xA;.completion-text {&#xA;color: #666;&#xA;margin-bottom: 2rem;&#xA;font-size: 1.1rem;&#xA;line-height: 1.5;&#xA;}&#xA;.completion-actions {&#xA;display: flex;&#xA;gap: 1rem;&#xA;justify-content: center;&#xA;flex-wrap: wrap;&#xA;}&#xA;.completion-actions .btn {&#xA;min-width: 120px;&#xA;}&#xA; &#xA;@media (max-width: 768px) {&#xA;.flashcards-container { padding: 0.75rem; gap: 0.75rem; }&#xA;.flashcards-header { flex-direction: column; align-items: flex-start; margin-bottom: 0.75rem; gap: 0.75rem; }&#xA;.flashcards-controls { flex-direction: column; align-items: flex-start; gap: 0.75rem; width: 100%; }&#xA;.mode-selector { width: 100%; justify-content: flex-start; }&#xA;.control-buttons { width: 100%; justify-content: flex-start; }&#xA;.progress-display { align-self: flex-start; }&#xA;.flashcard { height: clamp(180px, 30vh, 250px); }&#xA;.flashcard-wrapper { margin: 1rem 0; }&#xA;.flashcards-navigation { margin: 1rem 0; gap: 0.5rem; }&#xA;.card-content { padding: clamp(1.2rem, 4vw, 2rem); }&#xA;.difficulty-buttons { gap: 0.5rem; }&#xA;.progress-stats { grid-template-columns: repeat(3, 1fr); gap: 0.5rem; }&#xA;}&#xA;@media (max-width: 480px) {&#xA;.flashcards-container { padding: 0.5rem; }&#xA;.flashcard { height: clamp(150px, 28vh, 220px); }&#xA;.flashcard-wrapper { margin: 0.75rem 0; }&#xA;.flashcards-navigation { margin: 0.75rem 0; }&#xA;.card-content { padding: clamp(1rem, 3.5vw, 1.5rem); }&#xA;.completion-content { padding: 1.5rem; margin: 1rem; }&#xA;.completion-icon { font-size: 3rem; }&#xA;.completion-title { font-size: 1.5rem; }&#xA;.completion-text { font-size: 1rem; }&#xA;.completion-actions { flex-direction: column; align-items: center; }&#xA;.completion-actions .btn { width: 100%; max-width: 200px; }&#xA;.progress-stats { grid-template-columns: repeat(2, 1fr); }&#xA;.difficulty-buttons { flex-wrap: wrap; gap: 0.3rem; }&#xA;.difficulty-buttons .btn { flex: 1; min-width: 60px; font-size: 0.7rem; padding: 0.3rem 0.5rem; }&#xA; &#xA;.difficulty-buttons .btn { text-indent: -1ch; overflow: hidden; white-space: nowrap; }&#xA;}&#xA;@media (max-height: 500px) and (orientation: landscape) {&#xA;.flashcard { height: clamp(120px, 45vh, 180px); }&#xA;.flashcard-wrapper { margin: 0.5rem 0; }&#xA;.flashcards-navigation { margin: 0.5rem 0; gap: 0.3rem; }&#xA;.flashcards-header h3 { font-size: 1rem; }&#xA;.progress-stats { padding: 0.5rem; }&#xA;.card-content { padding: clamp(0.8rem, 3vw, 1.2rem); }&#xA;}&#xA;&lt;/style&gt;&#xA;&lt;script src=&#34;https://unpkg.com/@supabase/supabase-js@2&#34;&gt;&lt;/script&gt;&#xA;&lt;script&gt;&#xA;&#xA;const { createClient } = supabase;&#xA;const supabaseClient = createClient(&#xA;&#39;https://xjurrqzjvhzjweufgivl.supabase.co&#39;,&#xA;&#39;eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6InhqdXJycXpqdmh6andldWZnaXZsIiwicm9sZSI6ImFub24iLCJpYXQiOjE3NDg5NDUzMTIsImV4cCI6MjA2NDUyMTMxMn0.rimZk-g9-RmvQCbQJ5Phk0lKwOue6pPlgibO-LKHqmM&#39;&#xA;);&#xA;&#xA;let authCheckInProgress = false;&#xA;let lastAuthCheck = 0;&#xA;const AUTH_CHECK_THROTTLE = 5000; &#xA;async function updateAuthLink() {&#xA;const now = Date.now();&#xA;if (authCheckInProgress || (now - lastAuthCheck) &lt; AUTH_CHECK_THROTTLE) {&#xA;return; &#xA;}&#xA;authCheckInProgress = true;&#xA;lastAuthCheck = now;&#xA;const authLink = document.getElementById(&#39;auth-link&#39;);&#xA;if (!authLink) {&#xA;authCheckInProgress = false;&#xA;return;&#xA;}&#xA;try {&#xA;const { data: { session }, error } = await supabaseClient.auth.getSession();&#xA;if (error || !session?.user) {&#xA;authLink.textContent = &#39;Login&#39;;&#xA;authLink.href = &#39;/login/&#39;;&#xA;authLink.onclick = null;&#xA;return;&#xA;}&#xA;authLink.textContent = &#39;Logout&#39;;&#xA;authLink.onclick = async function(e) {&#xA;e.preventDefault();&#xA;try {&#xA;await supabaseClient.auth.signOut();&#xA;window.location.reload();&#xA;} catch (err) {&#xA;window.location.reload();&#xA;}&#xA;};&#xA;} catch (err) {&#xA;authLink.textContent = &#39;Login&#39;;&#xA;authLink.href = &#39;/login/&#39;;&#xA;authLink.onclick = null;&#xA;} finally {&#xA;authCheckInProgress = false;&#xA;}&#xA;}&#xA;&#xA;class FlashcardSystem {&#xA;constructor() {&#xA;&#xA;this.flashcards = [&#xA;&#xA;&#xA;{&#xA;term: &#34;\&#34;morphology\&#34;&#34;,&#xA;definition: &#34;\&#34;The study of word forms\&#34;&#34;,&#xA;stressed: &#34;\&#34;morph*ology\&#34;&#34;,&#xA;id: &#34;\&#34;53faa6b7f8a73ebe7d53ead07cb77f980ee9cf80e295a1c0053a68fbd0af1b8b\&#34;&#34;&#xA;},&#xA;&#xA;&#xA;&#xA;{&#xA;term: &#34;\&#34;magical\&#34;&#34;,&#xA;definition: &#34;\&#34;magique\&#34;&#34;,&#xA;stressed: &#34;\&#34;m*agical\&#34;&#34;,&#xA;id: &#34;\&#34;47bdf79bc36f83f0df5c7c69d190c5bb3f067ec90b8ba9b4a9a14a91a965c9a3\&#34;&#34;&#xA;},&#xA;&#xA;&#xA;&#xA;{&#xA;term: &#34;\&#34;power\&#34;&#34;,&#xA;definition: &#34;\&#34;pouvoir\&#34;&#34;,&#xA;stressed: &#34;\&#34;p*ower\&#34;&#34;,&#xA;id: &#34;\&#34;3538a59285153b54c7ecee097986460e8a64bcadbb6770de92bde9097296b431\&#34;&#34;&#xA;},&#xA;&#xA;&#xA;&#xA;{&#xA;term: &#34;\&#34;verb\&#34;&#34;,&#xA;definition: &#34;\&#34;verbe\&#34;&#34;,&#xA;stressed: &#34;\&#34;verb\&#34;&#34;,&#xA;id: &#34;\&#34;ecfc078827fafe48e0dbdbee4b77a4903d9a86faffaef2006c062fd64d2c6171\&#34;&#34;&#xA;},&#xA;&#xA;&#xA;&#xA;{&#xA;term: &#34;\&#34;noun\&#34;&#34;,&#xA;definition: &#34;\&#34;nom\&#34;&#34;,&#xA;stressed: &#34;\&#34;noun\&#34;&#34;,&#xA;id: &#34;\&#34;37f8071d14040db2a8de17086aa74f6a11172412d5538dbf4873bbd348dfe51c\&#34;&#34;&#xA;},&#xA;&#xA;&#xA;&#xA;{&#xA;term: &#34;\&#34;adjective\&#34;&#34;,&#xA;definition: &#34;\&#34;adjectif\&#34;&#34;,&#xA;stressed: &#34;\&#34;*adjective\&#34;&#34;,&#xA;id: &#34;\&#34;2ed11cf4d08b3fb3c065c9054e665e4675cdf0fc9b3df9797e535c963deb41e8\&#34;&#34;&#xA;},&#xA;&#xA;&#xA;&#xA;{&#xA;term: &#34;\&#34;regular\&#34;&#34;,&#xA;definition: &#34;\&#34;régulier\&#34;&#34;,&#xA;stressed: &#34;\&#34;r*egular\&#34;&#34;,&#xA;id: &#34;\&#34;dec5b1434432581f0ece3a7a1ed1df1ff2e1c37b1da0e8113eaa399ff727ff2a\&#34;&#34;&#xA;},&#xA;&#xA;&#xA;&#xA;{&#xA;term: &#34;\&#34;plural\&#34;&#34;,&#xA;definition: &#34;\&#34;pluriel\&#34;&#34;,&#xA;stressed: &#34;\&#34;pl*ural\&#34;&#34;,&#xA;id: &#34;\&#34;598dc3f6289c940e94e8ec4da1565ab1c3b010dc6d6d552392aa9dd5c87a167a\&#34;&#34;&#xA;},&#xA;&#xA;&#xA;&#xA;{&#xA;term: &#34;\&#34;genitive\&#34;&#34;,&#xA;definition: &#34;\&#34;génitif\&#34;&#34;,&#xA;stressed: &#34;\&#34;g*enitive\&#34;&#34;,&#xA;id: &#34;\&#34;bb63a669113e554e2cf99cd8b1b9e8b574b49f3241798fdd0a8ae4b0389e7097\&#34;&#34;&#xA;},&#xA;&#xA;&#xA;].filter(card =&gt; card.term.trim() &amp;&amp; card.definition.trim());&#xA;&#xA;this.setId = &#34;/chapters/power_of_english/&#34;.replace(/\/+$/, &#39;&#39;).replace(/^\//, &#39;&#39;);&#xA;this.setTitle = &#34;The Magic of English&#34;;&#xA;this.cardData = {};&#xA;this.sessionStats = { reviewed: 0 }; &#xA;this.reviewedInSession = new Set();&#xA;this.currentIndex = 0;&#xA;this.isFlipped = false;&#xA;this.studyMode = &#39;term-to-definition&#39;;&#xA;this.viewMode = &#39;browse&#39;; &#xA;this.cardOrder = [...Array(this.flashcards.length).keys()];&#xA;&#xA;this.initDOM();&#xA;this.setupEventListeners();&#xA;&#xA;this.loadProgress().then(() =&gt; {&#xA;this.initializeSession();&#xA;this.updateDisplay();&#xA;});&#xA;}&#xA;&#xA;&#xA;&#xA;&#xA;processStressedText(text) {&#xA;    if (!text) return text;&#xA;    &#xA;    &#xA;    &#xA;    let processed = text.replace(/(\s?)\*([ayeiouwAEYIOUáéíóúÁÉÍÓÚ])/g, &#39;$1&lt;span class=&#34;stressed-vowel&#34;&gt;$2&lt;/span&gt;&#39;);&#xA;    &#xA;    return processed;&#xA;}&#xA;&#xA;&#xA;&#xA;&#xA;initDOM() {&#xA;this.elements = {&#xA;flashcard: document.getElementById(&#39;flashcard&#39;),&#xA;cardQuestion: document.getElementById(&#39;card-question&#39;),&#xA;cardQuestionBack: document.getElementById(&#39;card-question-back&#39;),&#xA;cardAnswer: document.getElementById(&#39;card-answer&#39;),&#xA;currentCard: document.getElementById(&#39;current-card&#39;),&#xA;totalCards: document.getElementById(&#39;total-cards&#39;),&#xA;prevBtn: document.getElementById(&#39;prev-btn&#39;),&#xA;nextBtn: document.getElementById(&#39;next-btn&#39;),&#xA;modeToggleBtn: document.getElementById(&#39;mode-toggle-btn&#39;),&#xA;earlyReviewBtn: document.getElementById(&#39;early-review-btn&#39;),&#xA;resetBtn: document.getElementById(&#39;reset-progress&#39;),&#xA;againBtn: document.getElementById(&#39;again-btn&#39;),&#xA;hardBtn: document.getElementById(&#39;hard-btn&#39;),&#xA;mediumBtn: document.getElementById(&#39;medium-btn&#39;),&#xA;easyBtn: document.getElementById(&#39;easy-btn&#39;),&#xA;reviewedCount: document.getElementById(&#39;reviewed-count&#39;),&#xA;againCount: document.getElementById(&#39;again-count&#39;),&#xA;hardCount: document.getElementById(&#39;hard-count&#39;),&#xA;mediumCount: document.getElementById(&#39;medium-count&#39;),&#xA;easyCount: document.getElementById(&#39;easy-count&#39;),&#xA;reviewCount: document.getElementById(&#39;review-count&#39;),&#xA;completionMessage: document.getElementById(&#39;completion-message&#39;),&#xA;completionText: document.getElementById(&#39;completion-text&#39;),&#xA;earlyReviewOption: document.getElementById(&#39;early-review-option&#39;),&#xA;modeRadios: document.querySelectorAll(&#39;input[name=&#34;study-mode&#34;]&#39;)&#xA;};&#xA;}&#xA;setupEventListeners() {&#xA;this.elements.flashcard.addEventListener(&#39;click&#39;, () =&gt; this.flipCard());&#xA;this.elements.prevBtn.addEventListener(&#39;click&#39;, () =&gt; this.prevCard());&#xA;this.elements.nextBtn.addEventListener(&#39;click&#39;, () =&gt; this.nextCard());&#xA;this.elements.modeToggleBtn.addEventListener(&#39;click&#39;, () =&gt; this.toggleViewMode());&#xA;this.elements.earlyReviewBtn.addEventListener(&#39;click&#39;, () =&gt; this.handleEarlyReview());&#xA;this.elements.resetBtn.addEventListener(&#39;click&#39;, () =&gt; this.resetProgress());&#xA;&#xA;this.elements.againBtn.addEventListener(&#39;click&#39;, () =&gt; this.markDifficulty(&#39;again&#39;));&#xA;this.elements.hardBtn.addEventListener(&#39;click&#39;, () =&gt; this.markDifficulty(&#39;hard&#39;));&#xA;this.elements.mediumBtn.addEventListener(&#39;click&#39;, () =&gt; this.markDifficulty(&#39;medium&#39;));&#xA;this.elements.easyBtn.addEventListener(&#39;click&#39;, () =&gt; this.markDifficulty(&#39;easy&#39;));&#xA;this.elements.modeRadios.forEach(radio =&gt; {&#xA;radio.addEventListener(&#39;change&#39;, (e) =&gt; this.changeStudyMode(e.target.value));&#xA;});&#xA;document.getElementById(&#39;close-completion&#39;).addEventListener(&#39;click&#39;, () =&gt; {&#xA;this.elements.completionMessage.style.display = &#39;none&#39;;&#xA;});&#xA;document.getElementById(&#39;early-review-option&#39;).addEventListener(&#39;click&#39;, () =&gt; {&#xA;this.elements.completionMessage.style.display = &#39;none&#39;;&#xA;this.startEarlyReview();&#xA;});&#xA;document.getElementById(&#39;browse-all-option&#39;).addEventListener(&#39;click&#39;, () =&gt; {&#xA;this.elements.completionMessage.style.display = &#39;none&#39;;&#xA;this.startBrowseMode();&#xA;});&#xA;}&#xA;&#xA;shuffleArray(array) {&#xA;const shuffled = [...array]; &#xA;for (let i = shuffled.length - 1; i &gt; 0; i--) {&#xA;const j = Math.floor(Math.random() * (i + 1));&#xA;[shuffled[i], shuffled[j]] = [shuffled[j], shuffled[i]];&#xA;}&#xA;return shuffled;&#xA;}&#xA;&#xA;getDueCards(includeEarly = false) {&#xA;const now = Date.now();&#xA;const allIndices = [...Array(this.flashcards.length).keys()];&#xA;if (includeEarly) {&#xA;const earlyThreshold = now + (24 * 60 * 60 * 1000);&#xA;return allIndices.filter(idx =&gt; {&#xA;const card = this.cardData[idx];&#xA;return !card || !card.nextReview || card.nextReview &lt;= earlyThreshold;&#xA;});&#xA;} else {&#xA;return allIndices.filter(idx =&gt; {&#xA;const card = this.cardData[idx];&#xA;return !card || !card.nextReview || card.nextReview &lt;= now;&#xA;});&#xA;}&#xA;}&#xA;&#xA;updateCardWithSM2(cardIndex, difficulty) {&#xA;if (!this.cardData[cardIndex]) {&#xA;this.cardData[cardIndex] = {&#xA;interval: 0,&#xA;easeFactor: 2.5,&#xA;reviewCount: 0,&#xA;lastReviewed: Date.now(),&#xA;nextReview: Date.now()&#xA;};&#xA;}&#xA;const card = this.cardData[cardIndex];&#xA;card.reviewCount++;&#xA;card.lastReviewed = Date.now();&#xA;card.lastDifficulty = difficulty; &#xA;let quality;&#xA;switch (difficulty) {&#xA;case &#39;again&#39;: quality = 0; break;&#xA;case &#39;hard&#39;: quality = 2; break;&#xA;case &#39;medium&#39;: quality = 3; break;&#xA;case &#39;easy&#39;: quality = 5; break;&#xA;default: quality = 3;&#xA;}&#xA;&#xA;if (quality &gt;= 3) {&#xA;if (card.reviewCount === 1) {&#xA;card.interval = quality === 5 ? 2 : 1; &#xA;} else if (card.reviewCount === 2) {&#xA;card.interval = 6;&#xA;} else {&#xA;card.interval = Math.round(card.interval * card.easeFactor);&#xA;}&#xA;} else {&#xA;card.interval = quality === 0 ? 0.007 : 1; &#xA;}&#xA;&#xA;if (quality === 0) {&#xA;card.easeFactor = Math.max(1.3, card.easeFactor - 0.2);&#xA;} else if (quality === 2) {&#xA;card.easeFactor = Math.max(1.3, card.easeFactor - 0.15);&#xA;} else if (quality === 3) {&#xA;card.easeFactor = Math.max(1.3, card.easeFactor - 0.02);&#xA;} else if (quality === 5) {&#xA;card.easeFactor = Math.min(2.6, card.easeFactor + 0.1);&#xA;}&#xA;card.nextReview = card.lastReviewed + (card.interval * 24 * 60 * 60 * 1000);&#xA;}&#xA;&#xA;async markDifficulty(level) {&#xA;if (!this.isFlipped) {&#xA;this.flipCard();&#xA;return;&#xA;}&#xA;if (this.viewMode !== &#39;study&#39;) {&#xA;return;&#xA;}&#xA;const cardIndex = this.cardOrder[this.currentIndex];&#xA;&#xA;if (!this.reviewedInSession.has(cardIndex)) {&#xA;this.sessionStats.reviewed++;&#xA;this.reviewedInSession.add(cardIndex);&#xA;}&#xA;&#xA;this.updateCardWithSM2(cardIndex, level);&#xA;&#xA;await this.saveProgress();&#xA;this.updateStatsDisplay();&#xA;&#xA;if (level === &#39;again&#39;) {&#xA;if (this.currentIndex &lt; this.cardOrder.length - 1) {&#xA;this.currentIndex++;&#xA;} else {&#xA;this.currentIndex = 0;&#xA;}&#xA;this.updateCard();&#xA;} else {&#xA;&#xA;this.cardOrder.splice(this.currentIndex, 1);&#xA;if (this.currentIndex &gt;= this.cardOrder.length &amp;&amp; this.cardOrder.length &gt; 0) {&#xA;this.currentIndex = this.cardOrder.length - 1;&#xA;}&#xA;if (this.cardOrder.length &gt; 0) {&#xA;this.updateCard();&#xA;} else {&#xA;this.saveProgress();&#xA;this.showCompletionMessage();&#xA;}&#xA;}&#xA;}&#xA;&#xA;startStudyMode() {&#xA;const dueCards = this.getDueCards();&#xA;if (dueCards.length &gt; 0) {&#xA;this.viewMode = &#39;study&#39;;&#xA;&#xA;this.cardOrder = this.shuffleArray(dueCards);&#xA;this.currentIndex = 0;&#xA;this.updateModeButton(&#39;📚 Studying&#39;, &#39;btn-primary&#39;);&#xA;this.updateCard();&#xA;} else {&#xA;this.checkForEarlyReview();&#xA;}&#xA;}&#xA;startEarlyReview() {&#xA;const allEarly = this.getDueCards(true);&#xA;const dueNow = this.getDueCards(false);&#xA;const earlyOnly = allEarly.filter(idx =&gt; !dueNow.includes(idx));&#xA;if (earlyOnly.length &gt; 0) {&#xA;this.viewMode = &#39;study&#39;;&#xA;&#xA;this.cardOrder = this.shuffleArray(earlyOnly);&#xA;this.currentIndex = 0;&#xA;this.updateModeButton(&#39;📚 Studying&#39;, &#39;btn-primary&#39;);&#xA;this.updateCard();&#xA;} else {&#xA;alert(&#34;No cards are available for early review right now.&#34;);&#xA;}&#xA;}&#xA;startBrowseMode() {&#xA;this.viewMode = &#39;browse&#39;;&#xA;&#xA;this.cardOrder = [...Array(this.flashcards.length).keys()];&#xA;this.currentIndex = 0;&#xA;this.updateModeButton(&#39;📖 Browsing&#39;, &#39;btn-secondary&#39;);&#xA;this.updateCard();&#xA;}&#xA;checkForEarlyReview() {&#xA;const allEarly = this.getDueCards(true);&#xA;const dueNow = this.getDueCards(false);&#xA;const earlyCount = allEarly.length - dueNow.length;&#xA;if (earlyCount &gt; 0) {&#xA;const message = `No cards are due right now, but you have ${earlyCount} card${earlyCount !== 1 ? &#39;s&#39; : &#39;&#39;} due within 24 hours.\n\nWould you like to review them early?`;&#xA;if (confirm(message)) {&#xA;this.startEarlyReview();&#xA;} else {&#xA;this.viewMode = &#39;browse&#39;;&#xA;this.startBrowseMode();&#xA;}&#xA;} else {&#xA;this.showCompletionMessage();&#xA;this.viewMode = &#39;browse&#39;;&#xA;}&#xA;}&#xA;&#xA;updateModeButton(text, className) {&#xA;this.elements.modeToggleBtn.textContent = text;&#xA;this.elements.modeToggleBtn.className = `btn ${className}`;&#xA;&#xA;const difficultyButtons = document.querySelector(&#39;.difficulty-buttons&#39;);&#xA;if (difficultyButtons) {&#xA;if (this.viewMode === &#39;study&#39;) {&#xA;difficultyButtons.style.display = &#39;flex&#39;;&#xA;} else {&#xA;difficultyButtons.style.display = &#39;none&#39;;&#xA;}&#xA;}&#xA;}&#xA;toggleViewMode() {&#xA;if (this.viewMode === &#39;browse&#39;) {&#xA;this.startStudyMode();&#xA;} else {&#xA;this.startBrowseMode();&#xA;}&#xA;&#xA;this.saveProgressSilent();&#xA;}&#xA;handleEarlyReview() {&#xA;const allEarly = this.getDueCards(true);&#xA;const dueNow = this.getDueCards(false);&#xA;const earlyCount = allEarly.length - dueNow.length;&#xA;if (earlyCount &gt; 0) {&#xA;this.startEarlyReview();&#xA;} else if (dueNow.length &gt; 0) {&#xA;alert(&#34;You have cards due for review! Use the Study button instead.&#34;);&#xA;} else {&#xA;alert(&#34;No cards are available for early review right now.&#34;);&#xA;}&#xA;}&#xA;&#xA;updateCard() {&#xA;if (this.flashcards.length === 0) {&#xA;this.elements.cardQuestion.innerHTML = &#34;No flashcards available&#34;;&#xA;this.elements.cardQuestionBack.innerHTML = &#34;No flashcards available&#34;;&#xA;this.elements.cardAnswer.innerHTML = &#34;Please add lexicon data to the front matter&#34;;&#xA;return;&#xA;}&#xA;if (this.currentIndex &lt; 0 || this.currentIndex &gt;= this.cardOrder.length) {&#xA;this.currentIndex = 0;&#xA;}&#xA;const cardIndex = this.cardOrder[this.currentIndex];&#xA;const card = this.flashcards[cardIndex];&#xA;if (!card) {&#xA;console.error(&#39;Invalid card at index:&#39;, cardIndex);&#xA;return;&#xA;}&#xA;let question, answer;&#xA;if (this.studyMode === &#39;term-to-definition&#39;) {&#xA;&#xA;question = card.stressed || card.term;&#xA;answer = card.definition;&#xA;} else {&#xA;question = card.definition;&#xA;&#xA;answer = card.stressed || card.term;&#xA;}&#xA;&#xA;this.elements.cardQuestion.innerHTML = this.processStressedText(question);&#xA;this.elements.cardQuestionBack.innerHTML = this.processStressedText(question);&#xA;this.elements.cardAnswer.innerHTML = this.processStressedText(answer);&#xA;this.elements.currentCard.textContent = this.currentIndex + 1;&#xA;this.elements.totalCards.textContent = this.cardOrder.length;&#xA;&#xA;this.elements.prevBtn.disabled = this.currentIndex === 0;&#xA;this.elements.nextBtn.disabled = this.currentIndex === this.cardOrder.length - 1;&#xA;&#xA;this.isFlipped = false;&#xA;this.elements.flashcard.classList.remove(&#39;flipped&#39;);&#xA;}&#xA;&#xA;updateStatsDisplay() {&#xA;const totalReviewed = Object.values(this.cardData).filter(card =&gt; card &amp;&amp; card.reviewCount &gt; 0).length;&#xA;const needsReview = this.getDueCards().length;&#xA;&#xA;const difficultyStats = { again: 0, hard: 0, medium: 0, easy: 0 };&#xA;for (let i = 0; i &lt; this.flashcards.length; i++) {&#xA;const card = this.cardData[i];&#xA;if (card &amp;&amp; card.lastDifficulty) {&#xA;difficultyStats[card.lastDifficulty]++;&#xA;}&#xA;}&#xA;this.elements.reviewedCount.textContent = totalReviewed;&#xA;this.elements.reviewCount.textContent = needsReview;&#xA;&#xA;if (this.elements.againCount) this.elements.againCount.textContent = difficultyStats.again;&#xA;if (this.elements.hardCount) this.elements.hardCount.textContent = difficultyStats.hard;&#xA;if (this.elements.mediumCount) this.elements.mediumCount.textContent = difficultyStats.medium;&#xA;this.elements.easyCount.textContent = difficultyStats.easy;&#xA;}&#xA;updateDisplay() {&#xA;this.updateCard();&#xA;this.updateStatsDisplay();&#xA;&#xA;const radio = document.querySelector(`input[value=&#34;${this.studyMode}&#34;]`);&#xA;if (radio) radio.checked = true;&#xA;&#xA;if (this.viewMode === &#39;study&#39;) {&#xA;this.updateModeButton(&#39;📚 Studying&#39;, &#39;btn-primary&#39;);&#xA;} else {&#xA;this.updateModeButton(&#39;📖 Browsing&#39;, &#39;btn-secondary&#39;);&#xA;}&#xA;}&#xA;&#xA;flipCard() {&#xA;this.isFlipped = !this.isFlipped;&#xA;this.elements.flashcard.classList.toggle(&#39;flipped&#39;);&#xA;}&#xA;nextCard() {&#xA;if (this.currentIndex &lt; this.cardOrder.length - 1) {&#xA;this.currentIndex++;&#xA;this.updateCard();&#xA;&#xA;if (this.viewMode === &#39;study&#39;) {&#xA;this.saveProgressSilent();&#xA;}&#xA;}&#xA;}&#xA;prevCard() {&#xA;if (this.currentIndex &gt; 0) {&#xA;this.currentIndex--;&#xA;this.updateCard();&#xA;&#xA;if (this.viewMode === &#39;study&#39;) {&#xA;this.saveProgressSilent();&#xA;}&#xA;}&#xA;}&#xA;changeStudyMode(mode) {&#xA;this.studyMode = mode;&#xA;this.updateCard();&#xA;&#xA;this.saveProgressSilent();&#xA;}&#xA;&#xA;showCompletionMessage() {&#xA;this.viewMode = &#39;browse&#39;;&#xA;this.updateModeButton(&#39;📖 Browsing&#39;, &#39;btn-secondary&#39;);&#xA;const nextReview = this.getNextReviewTime();&#xA;const allEarly = this.getDueCards(true);&#xA;const dueNow = this.getDueCards(false);&#xA;const earlyCards = allEarly.length - dueNow.length;&#xA;let message = &#34;You&#39;ve reviewed all due cards!&#34;;&#xA;if (nextReview) {&#xA;const timeUntil = nextReview - Date.now();&#xA;const hoursUntil = Math.ceil(timeUntil / (1000 * 60 * 60));&#xA;const daysUntil = Math.ceil(timeUntil / (1000 * 60 * 60 * 24));&#xA;if (hoursUntil &lt; 24) {&#xA;message += ` Next cards will be ready in about ${hoursUntil} hour${hoursUntil !== 1 ? &#39;s&#39; : &#39;&#39;}.`;&#xA;} else {&#xA;message += ` Next cards will be ready in about ${daysUntil} day${daysUntil !== 1 ? &#39;s&#39; : &#39;&#39;}.`;&#xA;}&#xA;}&#xA;this.elements.completionText.textContent = message;&#xA;if (earlyCards &gt; 0) {&#xA;this.elements.earlyReviewOption.style.display = &#39;inline-block&#39;;&#xA;this.elements.earlyReviewOption.textContent = `⏰ Review ${earlyCards} Early Card${earlyCards !== 1 ? &#39;s&#39; : &#39;&#39;}`;&#xA;} else {&#xA;this.elements.earlyReviewOption.style.display = &#39;none&#39;;&#xA;}&#xA;this.elements.completionMessage.style.display = &#39;flex&#39;;&#xA;this.saveProgressSilent();&#xA;}&#xA;getNextReviewTime() {&#xA;const now = Date.now();&#xA;let earliest = null;&#xA;for (let i = 0; i &lt; this.flashcards.length; i++) {&#xA;const card = this.cardData[i];&#xA;if (card &amp;&amp; card.nextReview &amp;&amp; card.nextReview &gt; now) {&#xA;if (!earliest || card.nextReview &lt; earliest) {&#xA;earliest = card.nextReview;&#xA;}&#xA;}&#xA;}&#xA;return earliest;&#xA;}&#xA;&#xA;resetProgress() {&#xA;this.cardData = {};&#xA;this.sessionStats = { reviewed: 0 };&#xA;this.reviewedInSession = new Set();&#xA;this.viewMode = &#39;browse&#39;;&#xA;this.cardOrder = [...Array(this.flashcards.length).keys()];&#xA;this.currentIndex = 0;&#xA;this.updateDisplay();&#xA;this.saveProgressSilent();&#xA;}&#xA;&#xA;initializeSession() {&#xA;if (this.viewMode === &#39;study&#39;) {&#xA;const dueCards = this.getDueCards();&#xA;if (dueCards.length &gt; 0) {&#xA;&#xA;this.cardOrder = this.shuffleArray(dueCards);&#xA;this.currentIndex = 0;&#xA;this.updateModeButton(&#39;📚 Studying&#39;, &#39;btn-primary&#39;);&#xA;} else {&#xA;this.viewMode = &#39;browse&#39;;&#xA;this.cardOrder = [...Array(this.flashcards.length).keys()];&#xA;this.currentIndex = Math.min(this.currentIndex, this.cardOrder.length - 1);&#xA;this.updateModeButton(&#39;📖 Browsing&#39;, &#39;btn-secondary&#39;);&#xA;}&#xA;} else {&#xA;&#xA;this.cardOrder = [...Array(this.flashcards.length).keys()];&#xA;this.currentIndex = Math.min(this.currentIndex, this.cardOrder.length - 1);&#xA;this.updateModeButton(&#39;📖 Browsing&#39;, &#39;btn-secondary&#39;);&#xA;}&#xA;}&#xA;&#xA;async saveProgress() {&#xA;this.saveToLocalStorage();&#xA;try {&#xA;const { data: { session }, error } = await supabaseClient.auth.getSession();&#xA;if (error || !session?.user?.id) {&#xA;return;&#xA;}&#xA;const progressData = {&#xA;user_id: session.user.id,&#xA;set_id: this.setId,&#xA;set_title: this.setTitle,&#xA;card_data: {&#xA;cardOrder: this.cardOrder,&#xA;currentIndex: this.currentIndex,&#xA;studyMode: this.studyMode,&#xA;viewMode: this.viewMode,&#xA;cardData: this.cardData&#xA;},&#xA;stats: this.sessionStats,&#xA;updated_at: new Date().toISOString()&#xA;};&#xA;const { error: saveError } = await supabaseClient&#xA;.from(&#39;flashcard_progress&#39;)&#xA;.upsert(progressData, { onConflict: &#39;user_id,set_id&#39; });&#xA;if (saveError) {&#xA;console.error(&#39;Supabase save error:&#39;, saveError);&#xA;}&#xA;} catch (e) {&#xA;console.error(&#39;Error saving progress:&#39;, e);&#xA;}&#xA;}&#xA;&#xA;async saveProgressSilent() {&#xA;this.saveToLocalStorage();&#xA;try {&#xA;const { data: { session }, error } = await supabaseClient.auth.getSession();&#xA;if (error || !session?.user?.id) {&#xA;return;&#xA;}&#xA;const progressData = {&#xA;user_id: session.user.id,&#xA;set_id: this.setId,&#xA;set_title: this.setTitle,&#xA;card_data: {&#xA;cardOrder: this.cardOrder,&#xA;currentIndex: this.currentIndex,&#xA;studyMode: this.studyMode,&#xA;viewMode: this.viewMode,&#xA;cardData: this.cardData&#xA;},&#xA;stats: this.sessionStats,&#xA;updated_at: new Date().toISOString()&#xA;};&#xA;await supabaseClient&#xA;.from(&#39;flashcard_progress&#39;)&#xA;.upsert(progressData, { onConflict: &#39;user_id,set_id&#39; });&#xA;} catch (e) {&#xA;console.error(&#39;Error saving progress silently:&#39;, e);&#xA;}&#xA;}&#xA;async loadProgress() {&#xA;&#xA;this.cardData = {};&#xA;this.sessionStats = { reviewed: 0 };&#xA;this.reviewedInSession = new Set();&#xA;try {&#xA;const { data: { session }, error } = await supabaseClient.auth.getSession();&#xA;if (error || !session?.user?.id) {&#xA;this.loadFromLocalStorage();&#xA;return;&#xA;}&#xA;const { data, error: dbError } = await supabaseClient&#xA;.from(&#39;flashcard_progress&#39;)&#xA;.select(&#39;*&#39;)&#xA;.eq(&#39;user_id&#39;, session.user.id)&#xA;.eq(&#39;set_id&#39;, this.setId)&#xA;.single();&#xA;if (dbError &amp;&amp; dbError.code !== &#39;PGRST116&#39;) {&#xA;console.error(&#39;Database error:&#39;, dbError);&#xA;this.loadFromLocalStorage();&#xA;return;&#xA;}&#xA;if (data) {&#xA;this.loadFromData(data);&#xA;&#xA;await this.migrateLocalStorageIfNewer(data.updated_at);&#xA;} else {&#xA;this.loadFromLocalStorage();&#xA;if (session?.user) {&#xA;await this.saveProgressSilent();&#xA;}&#xA;}&#xA;} catch (e) {&#xA;console.error(&#39;Error loading progress:&#39;, e);&#xA;this.loadFromLocalStorage();&#xA;}&#xA;}&#xA;&#xA;loadFromData(data) {&#xA;if (data.card_data) {&#xA;this.cardOrder = this.validateArray(data.card_data.cardOrder, this.flashcards.length) ||&#xA;[...Array(this.flashcards.length).keys()];&#xA;this.cardData = this.validateCardData(data.card_data.cardData) || {};&#xA;this.currentIndex = Math.max(0, Math.min(data.card_data.currentIndex || 0, this.cardOrder.length - 1));&#xA;this.studyMode = [&#39;term-to-definition&#39;, &#39;definition-to-term&#39;].includes(data.card_data.studyMode) ?&#xA;data.card_data.studyMode : &#39;term-to-definition&#39;;&#xA;this.viewMode = [&#39;browse&#39;, &#39;study&#39;].includes(data.card_data.viewMode) ?&#xA;data.card_data.viewMode : &#39;browse&#39;;&#xA;}&#xA;if (data.stats &amp;&amp; typeof data.stats === &#39;object&#39;) {&#xA;this.sessionStats = {&#xA;reviewed: data.stats.reviewed || 0&#xA;};&#xA;}&#xA;}&#xA;loadFromLocalStorage() {&#xA;const storageKey = `flashcards_${this.setId}`;&#xA;const saved = localStorage.getItem(storageKey);&#xA;if (saved) {&#xA;try {&#xA;const data = JSON.parse(saved);&#xA;this.loadFromData({&#xA;card_data: {&#xA;cardOrder: data.cardOrder,&#xA;cardData: data.cardData,&#xA;currentIndex: data.currentIndex,&#xA;studyMode: data.studyMode,&#xA;viewMode: data.viewMode&#xA;},&#xA;stats: data.sessionStats&#xA;});&#xA;} catch (e) {&#xA;console.error(&#39;Error parsing localStorage:&#39;, e);&#xA;}&#xA;}&#xA;}&#xA;async migrateLocalStorageIfNewer(dbUpdatedAt) {&#xA;const storageKey = `flashcards_${this.setId}`;&#xA;const saved = localStorage.getItem(storageKey);&#xA;if (!saved) return;&#xA;try {&#xA;const localData = JSON.parse(saved);&#xA;const localUpdated = new Date(localData.lastUpdated || 0);&#xA;const dbUpdated = new Date(dbUpdatedAt);&#xA;if (localUpdated &gt; dbUpdated) {&#xA;this.loadFromData({&#xA;card_data: {&#xA;cardOrder: localData.cardOrder,&#xA;cardData: localData.cardData,&#xA;currentIndex: localData.currentIndex,&#xA;studyMode: localData.studyMode,&#xA;viewMode: localData.viewMode&#xA;},&#xA;stats: localData.sessionStats&#xA;});&#xA;await this.saveProgressSilent();&#xA;}&#xA;} catch (e) {&#xA;console.error(&#39;Error during migration:&#39;, e);&#xA;}&#xA;}&#xA;saveToLocalStorage() {&#xA;const storageKey = `flashcards_${this.setId}`;&#xA;const data = {&#xA;cardOrder: this.cardOrder,&#xA;currentIndex: this.currentIndex,&#xA;studyMode: this.studyMode,&#xA;viewMode: this.viewMode,&#xA;cardData: this.cardData,&#xA;sessionStats: this.sessionStats,&#xA;lastUpdated: new Date().toISOString(),&#xA;setTitle: this.setTitle&#xA;};&#xA;try {&#xA;localStorage.setItem(storageKey, JSON.stringify(data));&#xA;} catch (e) {&#xA;console.error(&#39;Error saving to localStorage:&#39;, e);&#xA;}&#xA;}&#xA;&#xA;validateArray(arr, expectedLength) {&#xA;if (!Array.isArray(arr) || arr.length !== expectedLength) return null;&#xA;return arr.every(idx =&gt; Number.isInteger(idx) &amp;&amp; idx &gt;= 0 &amp;&amp; idx &lt; expectedLength) ? arr : null;&#xA;}&#xA;validateCardData(data) {&#xA;if (!data || typeof data !== &#39;object&#39;) return null;&#xA;const validated = {};&#xA;for (const [key, value] of Object.entries(data)) {&#xA;if (value &amp;&amp; typeof value === &#39;object&#39; &amp;&amp;&#xA;typeof value.interval === &#39;number&#39; &amp;&amp;&#xA;typeof value.easeFactor === &#39;number&#39;) {&#xA;validated[key] = value;&#xA;}&#xA;}&#xA;return validated;&#xA;}&#xA;}&#xA;&#xA;document.addEventListener(&#39;DOMContentLoaded&#39;, () =&gt; {&#xA;updateAuthLink();&#xA;window.flashcardSystem = new FlashcardSystem();&#xA;});&#xA;&#xA;supabaseClient.auth.onAuthStateChange(async (event, session) =&gt; {&#xA;console.log(&#39;Auth state changed:&#39;, event);&#xA;updateAuthLink();&#xA;&#xA;});&#xA;&#xA;window.addEventListener(&#39;focus&#39;, () =&gt; {&#xA;setTimeout(updateAuthLink, 1000); &#xA;});&#xA;&lt;/script&gt;</description>
      
    </item>
    
    <item>
      <title>Flashcards</title>
      <link>https://premieres.stephanejacquet.fr/chapters/robinson/flashcards/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      
      <guid>https://premieres.stephanejacquet.fr/chapters/robinson/flashcards/</guid>
      <description>&lt;div class=&#34;flashcards-container&#34;&gt;&#xA;&lt;div style=&#34;display:flex; justify-content:space-between; align-items:baseline; gap:1rem; flex-wrap:wrap;&#34;&gt;&#xA;&lt;h2&gt;🧠 Robinson&amp;#39;s Myth and Avatars &amp;mdash; Flashcards&lt;/h2&gt;&#xA;&lt;a href=&#34;https://premieres.stephanejacquet.fr/login/&#34; id=&#34;auth-link&#34; class=&#34;login-link&#34; style=&#34;color:#007bff; text-decoration:none; font-size:0.9rem; white-space:nowrap;&#34;&gt;Login&lt;/a&gt;&#xA;&lt;/div&gt;&#xA;&lt;div class=&#34;flashcards-header&#34;&gt;&#xA;&lt;div class=&#34;flashcards-controls&#34;&gt;&#xA;&lt;div class=&#34;mode-selector&#34;&gt;&#xA;&lt;label class=&#34;mode-option&#34;&gt;&#xA;&lt;input type=&#34;radio&#34; name=&#34;study-mode&#34; value=&#34;term-to-definition&#34; checked&gt;&#xA;&lt;span&gt;Term → Definition&lt;/span&gt;&#xA;&lt;/label&gt;&#xA;&lt;label class=&#34;mode-option&#34;&gt;&#xA;&lt;input type=&#34;radio&#34; name=&#34;study-mode&#34; value=&#34;definition-to-term&#34;&gt;&#xA;&lt;span&gt;Definition → Term&lt;/span&gt;&#xA;&lt;/label&gt;&#xA;&lt;/div&gt;&#xA;&lt;div class=&#34;control-buttons&#34;&gt;&#xA;&lt;button id=&#34;mode-toggle-btn&#34; class=&#34;btn btn-secondary&#34;&gt;📖 Browse&lt;/button&gt;&#xA;&lt;button id=&#34;early-review-btn&#34; class=&#34;btn btn-info&#34;&gt;⏰ Early Review&lt;/button&gt;&#xA;&lt;button id=&#34;reset-progress&#34; class=&#34;btn btn-outline&#34;&gt;🔄 Reset&lt;/button&gt;&#xA;&lt;/div&gt;&#xA;&lt;div class=&#34;progress-display&#34;&gt;&#xA;&lt;span id=&#34;current-card&#34;&gt;1&lt;/span&gt; / &lt;span id=&#34;total-cards&#34;&gt;19&lt;/span&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&#xA;&lt;div class=&#34;flashcard-wrapper&#34;&gt;&#xA;&lt;div class=&#34;flashcard&#34; id=&#34;flashcard&#34;&gt;&#xA;&lt;div class=&#34;flashcard-inner&#34;&gt;&#xA;&lt;div class=&#34;flashcard-front&#34;&gt;&#xA;&lt;div class=&#34;card-content&#34;&gt;&#xA;&lt;div class=&#34;question&#34; id=&#34;card-question&#34;&gt;&lt;/div&gt;&#xA;&lt;div class=&#34;card-hint&#34;&gt;Tap to reveal answer&lt;/div&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&#xA;&lt;div class=&#34;flashcard-back&#34;&gt;&#xA;&lt;div class=&#34;card-content&#34;&gt;&#xA;&lt;div class=&#34;question-small&#34; id=&#34;card-question-back&#34;&gt;&lt;/div&gt;&#xA;&lt;div class=&#34;answer&#34; id=&#34;card-answer&#34;&gt;&lt;/div&gt;&#xA;&lt;div class=&#34;card-hint&#34;&gt;Tap to flip back&lt;/div&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&#xA;&lt;div class=&#34;flashcards-navigation&#34;&gt;&#xA;&lt;div class=&#34;nav-top&#34;&gt;&#xA;&lt;button id=&#34;next-btn&#34; class=&#34;btn btn-primary&#34;&gt;Next →&lt;/button&gt;&#xA;&lt;/div&gt;&#xA;&lt;div class=&#34;nav-middle&#34;&gt;&#xA;&lt;div class=&#34;difficulty-buttons&#34;&gt;&#xA;&lt;button id=&#34;again-btn&#34; class=&#34;btn btn-danger-dark&#34;&gt;🚫 Again&lt;/button&gt;&#xA;&lt;button id=&#34;hard-btn&#34; class=&#34;btn btn-danger&#34;&gt;😰 Hard&lt;/button&gt;&#xA;&lt;button id=&#34;medium-btn&#34; class=&#34;btn btn-warning&#34;&gt;🤔 Medium&lt;/button&gt;&#xA;&lt;button id=&#34;easy-btn&#34; class=&#34;btn btn-success&#34;&gt;😊 Easy&lt;/button&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&#xA;&lt;div class=&#34;nav-bottom&#34;&gt;&#xA;&lt;button id=&#34;prev-btn&#34; class=&#34;btn btn-primary&#34;&gt;← Previous&lt;/button&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&#xA;&lt;div class=&#34;progress-stats&#34;&gt;&#xA;&lt;div class=&#34;stat&#34;&gt;&#xA;&lt;span class=&#34;stat-label&#34;&gt;Reviewed:&lt;/span&gt;&#xA;&lt;span id=&#34;reviewed-count&#34;&gt;0&lt;/span&gt;&#xA;&lt;/div&gt;&#xA;&lt;div class=&#34;stat&#34;&gt;&#xA;&lt;span class=&#34;stat-label&#34;&gt;Again:&lt;/span&gt;&#xA;&lt;span id=&#34;again-count&#34;&gt;0&lt;/span&gt;&#xA;&lt;/div&gt;&#xA;&lt;div class=&#34;stat&#34;&gt;&#xA;&lt;span class=&#34;stat-label&#34;&gt;Hard:&lt;/span&gt;&#xA;&lt;span id=&#34;hard-count&#34;&gt;0&lt;/span&gt;&#xA;&lt;/div&gt;&#xA;&lt;div class=&#34;stat&#34;&gt;&#xA;&lt;span class=&#34;stat-label&#34;&gt;Medium:&lt;/span&gt;&#xA;&lt;span id=&#34;medium-count&#34;&gt;0&lt;/span&gt;&#xA;&lt;/div&gt;&#xA;&lt;div class=&#34;stat&#34;&gt;&#xA;&lt;span class=&#34;stat-label&#34;&gt;Easy:&lt;/span&gt;&#xA;&lt;span id=&#34;easy-count&#34;&gt;0&lt;/span&gt;&#xA;&lt;/div&gt;&#xA;&lt;div class=&#34;stat&#34;&gt;&#xA;&lt;span class=&#34;stat-label&#34;&gt;Due:&lt;/span&gt;&#xA;&lt;span id=&#34;review-count&#34;&gt;0&lt;/span&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&#xA;&lt;div class=&#34;completion-message&#34; id=&#34;completion-message&#34; style=&#34;display: none;&#34;&gt;&#xA;&lt;div class=&#34;completion-content&#34;&gt;&#xA;&lt;div class=&#34;completion-icon&#34;&gt;🎉&lt;/div&gt;&#xA;&lt;h3 class=&#34;completion-title&#34;&gt;Great Job!&lt;/h3&gt;&#xA;&lt;p class=&#34;completion-text&#34; id=&#34;completion-text&#34;&gt;&lt;/p&gt;&#xA;&lt;div class=&#34;completion-actions&#34;&gt;&#xA;&lt;button id=&#34;early-review-option&#34; class=&#34;btn btn-info&#34; style=&#34;display: none;&#34;&gt;⏰ Review Early Cards&lt;/button&gt;&#xA;&lt;button id=&#34;browse-all-option&#34; class=&#34;btn btn-secondary&#34;&gt;📖 Browse All Cards&lt;/button&gt;&#xA;&lt;button id=&#34;close-completion&#34; class=&#34;btn btn-primary&#34;&gt;✨ Done&lt;/button&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&#xA;&lt;style&gt;&#xA; &#xA;.stressed-vowel {&#xA;color: red !important;&#xA;font-weight: bold;&#xA;}&#xA; &#xA;.btn-danger-dark {&#xA;background: #8b0000;&#xA;color: white;&#xA;}&#xA;.btn-danger-dark:hover {&#xA;background: #a00000;&#xA;transform: translateY(-1px);&#xA;box-shadow: 0 2px 8px rgba(0,0,0,0.2);&#xA;}&#xA; &#xA;.flashcards-container {&#xA;max-width: 600px;&#xA;margin: 0 auto;&#xA;padding: 1rem;&#xA;font-family: -apple-system, BlinkMacSystemFont, &#39;Segoe UI&#39;, Roboto, sans-serif;&#xA;display: flex;&#xA;flex-direction: column;&#xA;box-sizing: border-box;&#xA;gap: 1rem;&#xA;}&#xA;.flashcards-header {&#xA;display: flex;&#xA;justify-content: space-between;&#xA;align-items: center;&#xA;margin-bottom: 1rem;&#xA;flex-wrap: wrap;&#xA;gap: 1rem;&#xA;}&#xA;.flashcards-header h3 {&#xA;margin: 0;&#xA;color: inherit;&#xA;font-size: clamp(1.2rem, 4vw, 1.5rem);&#xA;}&#xA;.flashcards-controls {&#xA;display: flex;&#xA;align-items: center;&#xA;gap: 1.2rem;&#xA;flex-wrap: wrap;&#xA;padding: 0.5rem 0;&#xA;}&#xA;.mode-selector {&#xA;display: flex;&#xA;gap: 0.8rem;&#xA;align-items: center;&#xA;}&#xA;.mode-option {&#xA;display: flex;&#xA;align-items: center;&#xA;gap: 0.5rem;&#xA;cursor: pointer;&#xA;padding: 0.5rem 0.75rem;&#xA;border-radius: 20px;&#xA;background: #f8f9fa;&#xA;border: 1px solid #ced4da;&#xA;color: #212529;&#xA;transition: all 0.2s ease;&#xA;font-size: clamp(0.75rem, 3vw, 0.9rem);&#xA;white-space: nowrap;&#xA;}&#xA;.mode-option span {&#xA;color: #212529;&#xA;}&#xA;.mode-option:hover {&#xA;background: #e9ecef;&#xA;}&#xA;.mode-option input[type=&#34;radio&#34;] {&#xA;margin: 0;&#xA;}&#xA;.mode-option input[type=&#34;radio&#34;]:checked + span {&#xA;font-weight: bold;&#xA;color: #007bff;&#xA;}&#xA;.control-buttons {&#xA;display: flex;&#xA;gap: 0.8rem;&#xA;}&#xA;.progress-display {&#xA;background: #f5f5f5;&#xA;padding: 0.5rem 0.75rem;&#xA;border-radius: 20px;&#xA;border: 1px solid #ced4da;&#xA;font-weight: bold;&#xA;color: #212529;&#xA;font-size: clamp(0.8rem, 3vw, 0.9rem);&#xA;}&#xA;.flashcard-wrapper {&#xA;perspective: 1000px;&#xA;margin: 1.5rem 0;&#xA;display: flex;&#xA;align-items: center;&#xA;}&#xA;.flashcard {&#xA;width: 100%;&#xA;height: clamp(220px, 35vh, 320px);&#xA;position: relative;&#xA;cursor: pointer;&#xA;transition: transform 0.3s ease;&#xA;}&#xA;.flashcard:hover {&#xA;transform: translateY(-2px);&#xA;}&#xA;.flashcard-inner {&#xA;position: relative;&#xA;width: 100%;&#xA;height: 100%;&#xA;text-align: center;&#xA;transition: transform 0.6s;&#xA;transform-style: preserve-3d;&#xA;}&#xA;.flashcard.flipped .flashcard-inner {&#xA;transform: rotateY(180deg);&#xA;}&#xA;.flashcard-front, .flashcard-back {&#xA;position: absolute;&#xA;width: 100%;&#xA;height: 100%;&#xA;backface-visibility: hidden;&#xA;border-radius: 15px;&#xA;box-shadow: 0 4px 20px rgba(0,0,0,0.1);&#xA;display: flex;&#xA;align-items: center;&#xA;justify-content: center;&#xA;}&#xA;.flashcard-front {&#xA;background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);&#xA;color: white;&#xA;}&#xA;.flashcard-back {&#xA;background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);&#xA;color: white;&#xA;transform: rotateY(180deg);&#xA;}&#xA;.card-content {&#xA;padding: clamp(1.5rem, 5vw, 2.5rem);&#xA;width: 100%;&#xA;height: 100%;&#xA;display: flex;&#xA;flex-direction: column;&#xA;justify-content: center;&#xA;box-sizing: border-box;&#xA;overflow: hidden;&#xA;}&#xA;&#xA; &#xA;.term, .question {&#xA;    font-size: clamp(1.4rem, 5vw, 2rem);&#xA;    font-weight: bold;&#xA;    margin-bottom: 1rem;&#xA;    text-shadow: 0 2px 4px rgba(0,0,0,0.3);&#xA;    line-height: 1.3;&#xA;    overflow-wrap: break-word;&#xA;    hyphens: auto;&#xA;    display: flex;&#xA;    align-items: center;&#xA;    justify-content: center;&#xA;    text-align: center;&#xA;    height: 100%;&#xA;    margin: 0 auto;&#xA;     &#xA;    white-space: pre-wrap;&#xA;}&#xA;&#xA;&#xA;&#xA;&#xA;&#xA;&#xA;&#xA;.term-small, .question-small {&#xA;font-size: clamp(0.85rem, 3.2vw, 1.1rem);&#xA;font-weight: bold;&#xA;margin-bottom: 0.75rem;&#xA;opacity: 0.8;&#xA;line-height: 1.3;&#xA;overflow-wrap: break-word;&#xA;text-align: center;&#xA;}&#xA;.definition, .answer {&#xA;font-size: clamp(1.4rem, 5vw, 2rem);&#xA;font-weight: bold;&#xA;margin-bottom: 1rem;&#xA;text-shadow: 0 2px 4px rgba(0,0,0,0.3);&#xA;line-height: 1.3;&#xA;overflow-wrap: break-word;&#xA;hyphens: auto;&#xA;flex: 1;&#xA;display: flex;&#xA;align-items: center;&#xA;justify-content: center;&#xA;text-align: center;&#xA;}&#xA;.card-hint {&#xA;font-size: clamp(0.7rem, 2.3vw, 0.85rem);&#xA;opacity: 0.7;&#xA;font-style: italic;&#xA;margin-top: auto;&#xA;text-align: center;&#xA;}&#xA;.flashcards-navigation {&#xA;display: flex;&#xA;flex-direction: column;&#xA;gap: 0.75rem;&#xA;margin: 1.5rem 0;&#xA;}&#xA;.nav-top, .nav-bottom {&#xA;display: flex;&#xA;justify-content: center;&#xA;}&#xA;.nav-middle {&#xA;display: flex;&#xA;justify-content: center;&#xA;}&#xA;.difficulty-buttons {&#xA;display: flex;&#xA;gap: 0.8rem;&#xA;justify-content: center;&#xA;flex-wrap: wrap;&#xA;}&#xA;.btn {&#xA;padding: clamp(0.4rem, 1.8vw, 0.6rem) clamp(0.8rem, 2.5vw, 1rem);&#xA;border: none;&#xA;border-radius: 8px;&#xA;cursor: pointer;&#xA;font-weight: 500;&#xA;transition: all 0.2s ease;&#xA;font-size: clamp(0.75rem, 2.8vw, 0.85rem);&#xA;white-space: nowrap;&#xA;min-width: fit-content;&#xA;}&#xA;.btn:hover {&#xA;transform: translateY(-1px);&#xA;box-shadow: 0 2px 8px rgba(0,0,0,0.2);&#xA;}&#xA;.btn-primary { background: #007bff; color: white; }&#xA;.btn-secondary { background: #6c757d; color: white; }&#xA;.btn-secondary:hover { background: #5a6268; }&#xA;.btn-success { background: #28a745; color: white; }&#xA;.btn-warning { background: #ffc107; color: #212529; }&#xA;.btn-danger { background: #dc3545; color: white; }&#xA;.btn-outline { background: white; border: 2px solid #495057; color: #212529; }&#xA;.btn-outline:hover { background: #495057; color: white; }&#xA;.btn-info { background: #17a2b8; color: white; }&#xA;.btn-info:hover { background: #138496; }&#xA;.btn:disabled {&#xA;opacity: 0.5;&#xA;cursor: not-allowed;&#xA;transform: none;&#xA;}&#xA;.progress-stats {&#xA;display: grid;&#xA;grid-template-columns: repeat(auto-fit, minmax(70px, 1fr));&#xA;gap: 0.75rem;&#xA;background: #f8f9fa;&#xA;border: 1px solid #ced4da;&#xA;padding: 0.75rem;&#xA;border-radius: 10px;&#xA;margin-top: 1rem;&#xA;}&#xA;.stat {&#xA;text-align: center;&#xA;flex: 1;&#xA;min-width: 70px;&#xA;}&#xA;.stat-label {&#xA;display: block;&#xA;font-size: clamp(0.65rem, 2.3vw, 0.75rem);&#xA;color: #666;&#xA;text-transform: uppercase;&#xA;letter-spacing: 0.5px;&#xA;}&#xA;.stat span:last-child {&#xA;display: block;&#xA;font-size: clamp(1rem, 3.5vw, 1.3rem);&#xA;font-weight: bold;&#xA;color: #333;&#xA;margin-top: 0.25rem;&#xA;}&#xA;.completion-message {&#xA;position: fixed;&#xA;top: 0;&#xA;left: 0;&#xA;width: 100%;&#xA;height: 100%;&#xA;background: rgba(0, 0, 0, 0.8);&#xA;display: flex;&#xA;align-items: center;&#xA;justify-content: center;&#xA;z-index: 1000;&#xA;backdrop-filter: blur(5px);&#xA;}&#xA;.completion-content {&#xA;background: white;&#xA;padding: 2rem;&#xA;border-radius: 20px;&#xA;text-align: center;&#xA;max-width: 90%;&#xA;max-height: 90%;&#xA;overflow-y: auto;&#xA;box-shadow: 0 20px 40px rgba(0, 0, 0, 0.3);&#xA;animation: completionSlideIn 0.3s ease-out;&#xA;}&#xA;@keyframes completionSlideIn {&#xA;from {&#xA;opacity: 0;&#xA;transform: translateY(-50px) scale(0.9);&#xA;}&#xA;to {&#xA;opacity: 1;&#xA;transform: translateY(0) scale(1);&#xA;}&#xA;}&#xA;.completion-icon {&#xA;font-size: 4rem;&#xA;margin-bottom: 1rem;&#xA;animation: bounce 1s ease-in-out infinite alternate;&#xA;}&#xA;@keyframes bounce {&#xA;from { transform: translateY(0); }&#xA;to { transform: translateY(-10px); }&#xA;}&#xA;.completion-title {&#xA;color: #333;&#xA;margin-bottom: 1rem;&#xA;font-size: 2rem;&#xA;font-weight: bold;&#xA;}&#xA;.completion-text {&#xA;color: #666;&#xA;margin-bottom: 2rem;&#xA;font-size: 1.1rem;&#xA;line-height: 1.5;&#xA;}&#xA;.completion-actions {&#xA;display: flex;&#xA;gap: 1rem;&#xA;justify-content: center;&#xA;flex-wrap: wrap;&#xA;}&#xA;.completion-actions .btn {&#xA;min-width: 120px;&#xA;}&#xA; &#xA;@media (max-width: 768px) {&#xA;.flashcards-container { padding: 0.75rem; gap: 0.75rem; }&#xA;.flashcards-header { flex-direction: column; align-items: flex-start; margin-bottom: 0.75rem; gap: 0.75rem; }&#xA;.flashcards-controls { flex-direction: column; align-items: flex-start; gap: 0.75rem; width: 100%; }&#xA;.mode-selector { width: 100%; justify-content: flex-start; }&#xA;.control-buttons { width: 100%; justify-content: flex-start; }&#xA;.progress-display { align-self: flex-start; }&#xA;.flashcard { height: clamp(180px, 30vh, 250px); }&#xA;.flashcard-wrapper { margin: 1rem 0; }&#xA;.flashcards-navigation { margin: 1rem 0; gap: 0.5rem; }&#xA;.card-content { padding: clamp(1.2rem, 4vw, 2rem); }&#xA;.difficulty-buttons { gap: 0.5rem; }&#xA;.progress-stats { grid-template-columns: repeat(3, 1fr); gap: 0.5rem; }&#xA;}&#xA;@media (max-width: 480px) {&#xA;.flashcards-container { padding: 0.5rem; }&#xA;.flashcard { height: clamp(150px, 28vh, 220px); }&#xA;.flashcard-wrapper { margin: 0.75rem 0; }&#xA;.flashcards-navigation { margin: 0.75rem 0; }&#xA;.card-content { padding: clamp(1rem, 3.5vw, 1.5rem); }&#xA;.completion-content { padding: 1.5rem; margin: 1rem; }&#xA;.completion-icon { font-size: 3rem; }&#xA;.completion-title { font-size: 1.5rem; }&#xA;.completion-text { font-size: 1rem; }&#xA;.completion-actions { flex-direction: column; align-items: center; }&#xA;.completion-actions .btn { width: 100%; max-width: 200px; }&#xA;.progress-stats { grid-template-columns: repeat(2, 1fr); }&#xA;.difficulty-buttons { flex-wrap: wrap; gap: 0.3rem; }&#xA;.difficulty-buttons .btn { flex: 1; min-width: 60px; font-size: 0.7rem; padding: 0.3rem 0.5rem; }&#xA; &#xA;.difficulty-buttons .btn { text-indent: -1ch; overflow: hidden; white-space: nowrap; }&#xA;}&#xA;@media (max-height: 500px) and (orientation: landscape) {&#xA;.flashcard { height: clamp(120px, 45vh, 180px); }&#xA;.flashcard-wrapper { margin: 0.5rem 0; }&#xA;.flashcards-navigation { margin: 0.5rem 0; gap: 0.3rem; }&#xA;.flashcards-header h3 { font-size: 1rem; }&#xA;.progress-stats { padding: 0.5rem; }&#xA;.card-content { padding: clamp(0.8rem, 3vw, 1.2rem); }&#xA;}&#xA;&lt;/style&gt;&#xA;&lt;script src=&#34;https://unpkg.com/@supabase/supabase-js@2&#34;&gt;&lt;/script&gt;&#xA;&lt;script&gt;&#xA;&#xA;const { createClient } = supabase;&#xA;const supabaseClient = createClient(&#xA;&#39;https://xjurrqzjvhzjweufgivl.supabase.co&#39;,&#xA;&#39;eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6InhqdXJycXpqdmh6andldWZnaXZsIiwicm9sZSI6ImFub24iLCJpYXQiOjE3NDg5NDUzMTIsImV4cCI6MjA2NDUyMTMxMn0.rimZk-g9-RmvQCbQJ5Phk0lKwOue6pPlgibO-LKHqmM&#39;&#xA;);&#xA;&#xA;let authCheckInProgress = false;&#xA;let lastAuthCheck = 0;&#xA;const AUTH_CHECK_THROTTLE = 5000; &#xA;async function updateAuthLink() {&#xA;const now = Date.now();&#xA;if (authCheckInProgress || (now - lastAuthCheck) &lt; AUTH_CHECK_THROTTLE) {&#xA;return; &#xA;}&#xA;authCheckInProgress = true;&#xA;lastAuthCheck = now;&#xA;const authLink = document.getElementById(&#39;auth-link&#39;);&#xA;if (!authLink) {&#xA;authCheckInProgress = false;&#xA;return;&#xA;}&#xA;try {&#xA;const { data: { session }, error } = await supabaseClient.auth.getSession();&#xA;if (error || !session?.user) {&#xA;authLink.textContent = &#39;Login&#39;;&#xA;authLink.href = &#39;/login/&#39;;&#xA;authLink.onclick = null;&#xA;return;&#xA;}&#xA;authLink.textContent = &#39;Logout&#39;;&#xA;authLink.onclick = async function(e) {&#xA;e.preventDefault();&#xA;try {&#xA;await supabaseClient.auth.signOut();&#xA;window.location.reload();&#xA;} catch (err) {&#xA;window.location.reload();&#xA;}&#xA;};&#xA;} catch (err) {&#xA;authLink.textContent = &#39;Login&#39;;&#xA;authLink.href = &#39;/login/&#39;;&#xA;authLink.onclick = null;&#xA;} finally {&#xA;authCheckInProgress = false;&#xA;}&#xA;}&#xA;&#xA;class FlashcardSystem {&#xA;constructor() {&#xA;&#xA;this.flashcards = [&#xA;&#xA;&#xA;{&#xA;term: &#34;\&#34;(to) hunt\&#34;&#34;,&#xA;definition: &#34;\&#34;chasser\&#34;&#34;,&#xA;stressed: &#34;\&#34;(to) hunt\&#34;&#34;,&#xA;id: &#34;\&#34;b69ee4978c0f275019bbd7a1eeb60dbb600887fac7a91434ca196f0e62b892c3\&#34;&#34;&#xA;},&#xA;&#xA;&#xA;&#xA;{&#xA;term: &#34;\&#34;jungle\&#34;&#34;,&#xA;definition: &#34;\&#34;la jungle\&#34;&#34;,&#xA;stressed: &#34;\&#34;j*ungle\&#34;&#34;,&#xA;id: &#34;\&#34;77ec54eb51f1bb08a17c5ee658ab0f212c450de74046718a8d8301c1c8935c90\&#34;&#34;&#xA;},&#xA;&#xA;&#xA;&#xA;{&#xA;term: &#34;\&#34;(to) escape\&#34;&#34;,&#xA;definition: &#34;\&#34;s&#39;échapper\&#34;&#34;,&#xA;stressed: &#34;\&#34;(to) esc*ape\&#34;&#34;,&#xA;id: &#34;\&#34;a88f7297e2954434ebb2b0b44e00175145b0ea22acbb5bef8497ecba94a5a185\&#34;&#34;&#xA;},&#xA;&#xA;&#xA;&#xA;{&#xA;term: &#34;\&#34;weapon\&#34;&#34;,&#xA;definition: &#34;\&#34;arme\&#34;&#34;,&#xA;stressed: &#34;\&#34;w*e*apon\&#34;&#34;,&#xA;id: &#34;\&#34;9460aef4de8eb1f2821552a9f227359fd04148d823a36c593d1bfb2eb3603a45\&#34;&#34;&#xA;},&#xA;&#xA;&#xA;&#xA;{&#xA;term: &#34;\&#34;alone\&#34;&#34;,&#xA;definition: &#34;\&#34;seul\&#34;&#34;,&#xA;stressed: &#34;\&#34;al*one\&#34;&#34;,&#xA;id: &#34;\&#34;3edf3f4d2b9c7781c92788a4a33667b1eea882d9cf1f2879eaa7bb1f75096329\&#34;&#34;&#xA;},&#xA;&#xA;&#xA;&#xA;{&#xA;term: &#34;\&#34;afraid\&#34;&#34;,&#xA;definition: &#34;\&#34;effrayé\&#34;&#34;,&#xA;stressed: &#34;\&#34;afr*a*id\&#34;&#34;,&#xA;id: &#34;\&#34;d410563d46f990391866d8dc76d0fdb053e81c9a5503870470efb3b0bb81bd6f\&#34;&#34;&#xA;},&#xA;&#xA;&#xA;&#xA;{&#xA;term: &#34;\&#34;survival\&#34;&#34;,&#xA;definition: &#34;\&#34;survie\&#34;&#34;,&#xA;stressed: &#34;\&#34;surv*ival\&#34;&#34;,&#xA;id: &#34;\&#34;c002eb37b09ebb32f2d3bff4574aa1b38948afee1e2414b02847153811a12c8b\&#34;&#34;&#xA;},&#xA;&#xA;&#xA;&#xA;{&#xA;term: &#34;\&#34;the wild / wilderness\&#34;&#34;,&#xA;definition: &#34;\&#34;la nature sauvage\&#34;&#34;,&#xA;stressed: &#34;\&#34;the wild / w*ilderness\&#34;&#34;,&#xA;id: &#34;\&#34;f2b5866b454730628da273a663e097e6016360b3a6eb4ac796c4404919245592\&#34;&#34;&#xA;},&#xA;&#xA;&#xA;&#xA;{&#xA;term: &#34;\&#34;drinkable water\&#34;&#34;,&#xA;definition: &#34;\&#34;eau potable\&#34;&#34;,&#xA;stressed: &#34;\&#34;dr*inkable w*ater\&#34;&#34;,&#xA;id: &#34;\&#34;89ae2828f60e9ad17586484d28e059bbba83c07395f21597e11b7a1900673272\&#34;&#34;&#xA;},&#xA;&#xA;&#xA;&#xA;{&#xA;term: &#34;\&#34;food supplies\&#34;&#34;,&#xA;definition: &#34;\&#34;réserve de nourriture\&#34;&#34;,&#xA;stressed: &#34;\&#34;f*o*od suppl*ies\&#34;&#34;,&#xA;id: &#34;\&#34;e270edd28ed7013f3181f054f5d015bd1e8700dac3c2191a9c7045fabc781a9a\&#34;&#34;&#xA;},&#xA;&#xA;&#xA;&#xA;{&#xA;term: &#34;\&#34;shelter\&#34;&#34;,&#xA;definition: &#34;\&#34;abri\&#34;&#34;,&#xA;stressed: &#34;\&#34;sh*elter\&#34;&#34;,&#xA;id: &#34;\&#34;45dd9d933199b4e70491f03258caaab1755e84271a7bf95cbf749ea0b1f6e61e\&#34;&#34;&#xA;},&#xA;&#xA;&#xA;&#xA;{&#xA;term: &#34;\&#34;knife\&#34;&#34;,&#xA;definition: &#34;\&#34;couteau\&#34;&#34;,&#xA;stressed: &#34;\&#34;knife\&#34;&#34;,&#xA;id: &#34;\&#34;07f79954999e7faea53b49bf17e1395e960156bb6d104f7936522d92c9819803\&#34;&#34;&#xA;},&#xA;&#xA;&#xA;&#xA;{&#xA;term: &#34;\&#34;rope\&#34;&#34;,&#xA;definition: &#34;\&#34;corde\&#34;&#34;,&#xA;stressed: &#34;\&#34;rope\&#34;&#34;,&#xA;id: &#34;\&#34;f90b9674fccbb13e8580f3bca6dc34dc19f58992660b4d2ae5ebb50530512644\&#34;&#34;&#xA;},&#xA;&#xA;&#xA;&#xA;{&#xA;term: &#34;\&#34;storm\&#34;&#34;,&#xA;definition: &#34;\&#34;tempête\&#34;&#34;,&#xA;stressed: &#34;\&#34;storm\&#34;&#34;,&#xA;id: &#34;\&#34;e2868b6d49c25c71edf7a6753fa6a3b4a4f9d4bba9086b10147acad86e85e533\&#34;&#34;&#xA;},&#xA;&#xA;&#xA;&#xA;{&#xA;term: &#34;\&#34;desert island\&#34;&#34;,&#xA;definition: &#34;\&#34;île déserte\&#34;&#34;,&#xA;stressed: &#34;\&#34;d*esert *island\&#34;&#34;,&#xA;id: &#34;\&#34;9467c61bdafc6876ac1bfe4e32f46c99cfec8bf5bde24b5c96ad1fe654b1d170\&#34;&#34;&#xA;},&#xA;&#xA;&#xA;&#xA;{&#xA;term: &#34;\&#34;a shipwrecked man\&#34;&#34;,&#xA;definition: &#34;\&#34;un naufragé\&#34;&#34;,&#xA;stressed: &#34;\&#34;a sh*ipwrecked man\&#34;&#34;,&#xA;id: &#34;\&#34;8a25691eb75a1f4420a7e1a645992ad2477db04e222be728c02146fa2ef37690\&#34;&#34;&#xA;},&#xA;&#xA;&#xA;&#xA;{&#xA;term: &#34;\&#34;rescue\&#34;&#34;,&#xA;definition: &#34;\&#34;secourir\&#34;&#34;,&#xA;stressed: &#34;\&#34;r*escue\&#34;&#34;,&#xA;id: &#34;\&#34;1435b3c05e79e1be8d30b1c53fae663f0b629c72e3a93fc4015561a1db56d9ee\&#34;&#34;&#xA;},&#xA;&#xA;&#xA;&#xA;{&#xA;term: &#34;\&#34;shipwreck\&#34;&#34;,&#xA;definition: &#34;\&#34;naufrage\&#34;&#34;,&#xA;stressed: &#34;\&#34;sh*ipwreck\&#34;&#34;,&#xA;id: &#34;\&#34;a4f43abe728deee58564696f2bd87d2a939bf14102adafc4c0cc62a7a5a375ed\&#34;&#34;&#xA;},&#xA;&#xA;&#xA;&#xA;{&#xA;term: &#34;\&#34;castaway\&#34;&#34;,&#xA;definition: &#34;\&#34;isolated/cut off from civilisation\&#34;&#34;,&#xA;stressed: &#34;\&#34;c*astaway\&#34;&#34;,&#xA;id: &#34;\&#34;bd7b211d11a1dcec52a64584c44eda9ca51a67c75005e2d77337223457dbeaa2\&#34;&#34;&#xA;},&#xA;&#xA;&#xA;].filter(card =&gt; card.term.trim() &amp;&amp; card.definition.trim());&#xA;&#xA;this.setId = &#34;/chapters/robinson/&#34;.replace(/\/+$/, &#39;&#39;).replace(/^\//, &#39;&#39;);&#xA;this.setTitle = &#34;Robinson&#39;s Myth and Avatars&#34;;&#xA;this.cardData = {};&#xA;this.sessionStats = { reviewed: 0 }; &#xA;this.reviewedInSession = new Set();&#xA;this.currentIndex = 0;&#xA;this.isFlipped = false;&#xA;this.studyMode = &#39;term-to-definition&#39;;&#xA;this.viewMode = &#39;browse&#39;; &#xA;this.cardOrder = [...Array(this.flashcards.length).keys()];&#xA;&#xA;this.initDOM();&#xA;this.setupEventListeners();&#xA;&#xA;this.loadProgress().then(() =&gt; {&#xA;this.initializeSession();&#xA;this.updateDisplay();&#xA;});&#xA;}&#xA;&#xA;&#xA;&#xA;&#xA;processStressedText(text) {&#xA;    if (!text) return text;&#xA;    &#xA;    &#xA;    &#xA;    let processed = text.replace(/(\s?)\*([ayeiouwAEYIOUáéíóúÁÉÍÓÚ])/g, &#39;$1&lt;span class=&#34;stressed-vowel&#34;&gt;$2&lt;/span&gt;&#39;);&#xA;    &#xA;    return processed;&#xA;}&#xA;&#xA;&#xA;&#xA;&#xA;initDOM() {&#xA;this.elements = {&#xA;flashcard: document.getElementById(&#39;flashcard&#39;),&#xA;cardQuestion: document.getElementById(&#39;card-question&#39;),&#xA;cardQuestionBack: document.getElementById(&#39;card-question-back&#39;),&#xA;cardAnswer: document.getElementById(&#39;card-answer&#39;),&#xA;currentCard: document.getElementById(&#39;current-card&#39;),&#xA;totalCards: document.getElementById(&#39;total-cards&#39;),&#xA;prevBtn: document.getElementById(&#39;prev-btn&#39;),&#xA;nextBtn: document.getElementById(&#39;next-btn&#39;),&#xA;modeToggleBtn: document.getElementById(&#39;mode-toggle-btn&#39;),&#xA;earlyReviewBtn: document.getElementById(&#39;early-review-btn&#39;),&#xA;resetBtn: document.getElementById(&#39;reset-progress&#39;),&#xA;againBtn: document.getElementById(&#39;again-btn&#39;),&#xA;hardBtn: document.getElementById(&#39;hard-btn&#39;),&#xA;mediumBtn: document.getElementById(&#39;medium-btn&#39;),&#xA;easyBtn: document.getElementById(&#39;easy-btn&#39;),&#xA;reviewedCount: document.getElementById(&#39;reviewed-count&#39;),&#xA;againCount: document.getElementById(&#39;again-count&#39;),&#xA;hardCount: document.getElementById(&#39;hard-count&#39;),&#xA;mediumCount: document.getElementById(&#39;medium-count&#39;),&#xA;easyCount: document.getElementById(&#39;easy-count&#39;),&#xA;reviewCount: document.getElementById(&#39;review-count&#39;),&#xA;completionMessage: document.getElementById(&#39;completion-message&#39;),&#xA;completionText: document.getElementById(&#39;completion-text&#39;),&#xA;earlyReviewOption: document.getElementById(&#39;early-review-option&#39;),&#xA;modeRadios: document.querySelectorAll(&#39;input[name=&#34;study-mode&#34;]&#39;)&#xA;};&#xA;}&#xA;setupEventListeners() {&#xA;this.elements.flashcard.addEventListener(&#39;click&#39;, () =&gt; this.flipCard());&#xA;this.elements.prevBtn.addEventListener(&#39;click&#39;, () =&gt; this.prevCard());&#xA;this.elements.nextBtn.addEventListener(&#39;click&#39;, () =&gt; this.nextCard());&#xA;this.elements.modeToggleBtn.addEventListener(&#39;click&#39;, () =&gt; this.toggleViewMode());&#xA;this.elements.earlyReviewBtn.addEventListener(&#39;click&#39;, () =&gt; this.handleEarlyReview());&#xA;this.elements.resetBtn.addEventListener(&#39;click&#39;, () =&gt; this.resetProgress());&#xA;&#xA;this.elements.againBtn.addEventListener(&#39;click&#39;, () =&gt; this.markDifficulty(&#39;again&#39;));&#xA;this.elements.hardBtn.addEventListener(&#39;click&#39;, () =&gt; this.markDifficulty(&#39;hard&#39;));&#xA;this.elements.mediumBtn.addEventListener(&#39;click&#39;, () =&gt; this.markDifficulty(&#39;medium&#39;));&#xA;this.elements.easyBtn.addEventListener(&#39;click&#39;, () =&gt; this.markDifficulty(&#39;easy&#39;));&#xA;this.elements.modeRadios.forEach(radio =&gt; {&#xA;radio.addEventListener(&#39;change&#39;, (e) =&gt; this.changeStudyMode(e.target.value));&#xA;});&#xA;document.getElementById(&#39;close-completion&#39;).addEventListener(&#39;click&#39;, () =&gt; {&#xA;this.elements.completionMessage.style.display = &#39;none&#39;;&#xA;});&#xA;document.getElementById(&#39;early-review-option&#39;).addEventListener(&#39;click&#39;, () =&gt; {&#xA;this.elements.completionMessage.style.display = &#39;none&#39;;&#xA;this.startEarlyReview();&#xA;});&#xA;document.getElementById(&#39;browse-all-option&#39;).addEventListener(&#39;click&#39;, () =&gt; {&#xA;this.elements.completionMessage.style.display = &#39;none&#39;;&#xA;this.startBrowseMode();&#xA;});&#xA;}&#xA;&#xA;shuffleArray(array) {&#xA;const shuffled = [...array]; &#xA;for (let i = shuffled.length - 1; i &gt; 0; i--) {&#xA;const j = Math.floor(Math.random() * (i + 1));&#xA;[shuffled[i], shuffled[j]] = [shuffled[j], shuffled[i]];&#xA;}&#xA;return shuffled;&#xA;}&#xA;&#xA;getDueCards(includeEarly = false) {&#xA;const now = Date.now();&#xA;const allIndices = [...Array(this.flashcards.length).keys()];&#xA;if (includeEarly) {&#xA;const earlyThreshold = now + (24 * 60 * 60 * 1000);&#xA;return allIndices.filter(idx =&gt; {&#xA;const card = this.cardData[idx];&#xA;return !card || !card.nextReview || card.nextReview &lt;= earlyThreshold;&#xA;});&#xA;} else {&#xA;return allIndices.filter(idx =&gt; {&#xA;const card = this.cardData[idx];&#xA;return !card || !card.nextReview || card.nextReview &lt;= now;&#xA;});&#xA;}&#xA;}&#xA;&#xA;updateCardWithSM2(cardIndex, difficulty) {&#xA;if (!this.cardData[cardIndex]) {&#xA;this.cardData[cardIndex] = {&#xA;interval: 0,&#xA;easeFactor: 2.5,&#xA;reviewCount: 0,&#xA;lastReviewed: Date.now(),&#xA;nextReview: Date.now()&#xA;};&#xA;}&#xA;const card = this.cardData[cardIndex];&#xA;card.reviewCount++;&#xA;card.lastReviewed = Date.now();&#xA;card.lastDifficulty = difficulty; &#xA;let quality;&#xA;switch (difficulty) {&#xA;case &#39;again&#39;: quality = 0; break;&#xA;case &#39;hard&#39;: quality = 2; break;&#xA;case &#39;medium&#39;: quality = 3; break;&#xA;case &#39;easy&#39;: quality = 5; break;&#xA;default: quality = 3;&#xA;}&#xA;&#xA;if (quality &gt;= 3) {&#xA;if (card.reviewCount === 1) {&#xA;card.interval = quality === 5 ? 2 : 1; &#xA;} else if (card.reviewCount === 2) {&#xA;card.interval = 6;&#xA;} else {&#xA;card.interval = Math.round(card.interval * card.easeFactor);&#xA;}&#xA;} else {&#xA;card.interval = quality === 0 ? 0.007 : 1; &#xA;}&#xA;&#xA;if (quality === 0) {&#xA;card.easeFactor = Math.max(1.3, card.easeFactor - 0.2);&#xA;} else if (quality === 2) {&#xA;card.easeFactor = Math.max(1.3, card.easeFactor - 0.15);&#xA;} else if (quality === 3) {&#xA;card.easeFactor = Math.max(1.3, card.easeFactor - 0.02);&#xA;} else if (quality === 5) {&#xA;card.easeFactor = Math.min(2.6, card.easeFactor + 0.1);&#xA;}&#xA;card.nextReview = card.lastReviewed + (card.interval * 24 * 60 * 60 * 1000);&#xA;}&#xA;&#xA;async markDifficulty(level) {&#xA;if (!this.isFlipped) {&#xA;this.flipCard();&#xA;return;&#xA;}&#xA;if (this.viewMode !== &#39;study&#39;) {&#xA;return;&#xA;}&#xA;const cardIndex = this.cardOrder[this.currentIndex];&#xA;&#xA;if (!this.reviewedInSession.has(cardIndex)) {&#xA;this.sessionStats.reviewed++;&#xA;this.reviewedInSession.add(cardIndex);&#xA;}&#xA;&#xA;this.updateCardWithSM2(cardIndex, level);&#xA;&#xA;await this.saveProgress();&#xA;this.updateStatsDisplay();&#xA;&#xA;if (level === &#39;again&#39;) {&#xA;if (this.currentIndex &lt; this.cardOrder.length - 1) {&#xA;this.currentIndex++;&#xA;} else {&#xA;this.currentIndex = 0;&#xA;}&#xA;this.updateCard();&#xA;} else {&#xA;&#xA;this.cardOrder.splice(this.currentIndex, 1);&#xA;if (this.currentIndex &gt;= this.cardOrder.length &amp;&amp; this.cardOrder.length &gt; 0) {&#xA;this.currentIndex = this.cardOrder.length - 1;&#xA;}&#xA;if (this.cardOrder.length &gt; 0) {&#xA;this.updateCard();&#xA;} else {&#xA;this.saveProgress();&#xA;this.showCompletionMessage();&#xA;}&#xA;}&#xA;}&#xA;&#xA;startStudyMode() {&#xA;const dueCards = this.getDueCards();&#xA;if (dueCards.length &gt; 0) {&#xA;this.viewMode = &#39;study&#39;;&#xA;&#xA;this.cardOrder = this.shuffleArray(dueCards);&#xA;this.currentIndex = 0;&#xA;this.updateModeButton(&#39;📚 Studying&#39;, &#39;btn-primary&#39;);&#xA;this.updateCard();&#xA;} else {&#xA;this.checkForEarlyReview();&#xA;}&#xA;}&#xA;startEarlyReview() {&#xA;const allEarly = this.getDueCards(true);&#xA;const dueNow = this.getDueCards(false);&#xA;const earlyOnly = allEarly.filter(idx =&gt; !dueNow.includes(idx));&#xA;if (earlyOnly.length &gt; 0) {&#xA;this.viewMode = &#39;study&#39;;&#xA;&#xA;this.cardOrder = this.shuffleArray(earlyOnly);&#xA;this.currentIndex = 0;&#xA;this.updateModeButton(&#39;📚 Studying&#39;, &#39;btn-primary&#39;);&#xA;this.updateCard();&#xA;} else {&#xA;alert(&#34;No cards are available for early review right now.&#34;);&#xA;}&#xA;}&#xA;startBrowseMode() {&#xA;this.viewMode = &#39;browse&#39;;&#xA;&#xA;this.cardOrder = [...Array(this.flashcards.length).keys()];&#xA;this.currentIndex = 0;&#xA;this.updateModeButton(&#39;📖 Browsing&#39;, &#39;btn-secondary&#39;);&#xA;this.updateCard();&#xA;}&#xA;checkForEarlyReview() {&#xA;const allEarly = this.getDueCards(true);&#xA;const dueNow = this.getDueCards(false);&#xA;const earlyCount = allEarly.length - dueNow.length;&#xA;if (earlyCount &gt; 0) {&#xA;const message = `No cards are due right now, but you have ${earlyCount} card${earlyCount !== 1 ? &#39;s&#39; : &#39;&#39;} due within 24 hours.\n\nWould you like to review them early?`;&#xA;if (confirm(message)) {&#xA;this.startEarlyReview();&#xA;} else {&#xA;this.viewMode = &#39;browse&#39;;&#xA;this.startBrowseMode();&#xA;}&#xA;} else {&#xA;this.showCompletionMessage();&#xA;this.viewMode = &#39;browse&#39;;&#xA;}&#xA;}&#xA;&#xA;updateModeButton(text, className) {&#xA;this.elements.modeToggleBtn.textContent = text;&#xA;this.elements.modeToggleBtn.className = `btn ${className}`;&#xA;&#xA;const difficultyButtons = document.querySelector(&#39;.difficulty-buttons&#39;);&#xA;if (difficultyButtons) {&#xA;if (this.viewMode === &#39;study&#39;) {&#xA;difficultyButtons.style.display = &#39;flex&#39;;&#xA;} else {&#xA;difficultyButtons.style.display = &#39;none&#39;;&#xA;}&#xA;}&#xA;}&#xA;toggleViewMode() {&#xA;if (this.viewMode === &#39;browse&#39;) {&#xA;this.startStudyMode();&#xA;} else {&#xA;this.startBrowseMode();&#xA;}&#xA;&#xA;this.saveProgressSilent();&#xA;}&#xA;handleEarlyReview() {&#xA;const allEarly = this.getDueCards(true);&#xA;const dueNow = this.getDueCards(false);&#xA;const earlyCount = allEarly.length - dueNow.length;&#xA;if (earlyCount &gt; 0) {&#xA;this.startEarlyReview();&#xA;} else if (dueNow.length &gt; 0) {&#xA;alert(&#34;You have cards due for review! Use the Study button instead.&#34;);&#xA;} else {&#xA;alert(&#34;No cards are available for early review right now.&#34;);&#xA;}&#xA;}&#xA;&#xA;updateCard() {&#xA;if (this.flashcards.length === 0) {&#xA;this.elements.cardQuestion.innerHTML = &#34;No flashcards available&#34;;&#xA;this.elements.cardQuestionBack.innerHTML = &#34;No flashcards available&#34;;&#xA;this.elements.cardAnswer.innerHTML = &#34;Please add lexicon data to the front matter&#34;;&#xA;return;&#xA;}&#xA;if (this.currentIndex &lt; 0 || this.currentIndex &gt;= this.cardOrder.length) {&#xA;this.currentIndex = 0;&#xA;}&#xA;const cardIndex = this.cardOrder[this.currentIndex];&#xA;const card = this.flashcards[cardIndex];&#xA;if (!card) {&#xA;console.error(&#39;Invalid card at index:&#39;, cardIndex);&#xA;return;&#xA;}&#xA;let question, answer;&#xA;if (this.studyMode === &#39;term-to-definition&#39;) {&#xA;&#xA;question = card.stressed || card.term;&#xA;answer = card.definition;&#xA;} else {&#xA;question = card.definition;&#xA;&#xA;answer = card.stressed || card.term;&#xA;}&#xA;&#xA;this.elements.cardQuestion.innerHTML = this.processStressedText(question);&#xA;this.elements.cardQuestionBack.innerHTML = this.processStressedText(question);&#xA;this.elements.cardAnswer.innerHTML = this.processStressedText(answer);&#xA;this.elements.currentCard.textContent = this.currentIndex + 1;&#xA;this.elements.totalCards.textContent = this.cardOrder.length;&#xA;&#xA;this.elements.prevBtn.disabled = this.currentIndex === 0;&#xA;this.elements.nextBtn.disabled = this.currentIndex === this.cardOrder.length - 1;&#xA;&#xA;this.isFlipped = false;&#xA;this.elements.flashcard.classList.remove(&#39;flipped&#39;);&#xA;}&#xA;&#xA;updateStatsDisplay() {&#xA;const totalReviewed = Object.values(this.cardData).filter(card =&gt; card &amp;&amp; card.reviewCount &gt; 0).length;&#xA;const needsReview = this.getDueCards().length;&#xA;&#xA;const difficultyStats = { again: 0, hard: 0, medium: 0, easy: 0 };&#xA;for (let i = 0; i &lt; this.flashcards.length; i++) {&#xA;const card = this.cardData[i];&#xA;if (card &amp;&amp; card.lastDifficulty) {&#xA;difficultyStats[card.lastDifficulty]++;&#xA;}&#xA;}&#xA;this.elements.reviewedCount.textContent = totalReviewed;&#xA;this.elements.reviewCount.textContent = needsReview;&#xA;&#xA;if (this.elements.againCount) this.elements.againCount.textContent = difficultyStats.again;&#xA;if (this.elements.hardCount) this.elements.hardCount.textContent = difficultyStats.hard;&#xA;if (this.elements.mediumCount) this.elements.mediumCount.textContent = difficultyStats.medium;&#xA;this.elements.easyCount.textContent = difficultyStats.easy;&#xA;}&#xA;updateDisplay() {&#xA;this.updateCard();&#xA;this.updateStatsDisplay();&#xA;&#xA;const radio = document.querySelector(`input[value=&#34;${this.studyMode}&#34;]`);&#xA;if (radio) radio.checked = true;&#xA;&#xA;if (this.viewMode === &#39;study&#39;) {&#xA;this.updateModeButton(&#39;📚 Studying&#39;, &#39;btn-primary&#39;);&#xA;} else {&#xA;this.updateModeButton(&#39;📖 Browsing&#39;, &#39;btn-secondary&#39;);&#xA;}&#xA;}&#xA;&#xA;flipCard() {&#xA;this.isFlipped = !this.isFlipped;&#xA;this.elements.flashcard.classList.toggle(&#39;flipped&#39;);&#xA;}&#xA;nextCard() {&#xA;if (this.currentIndex &lt; this.cardOrder.length - 1) {&#xA;this.currentIndex++;&#xA;this.updateCard();&#xA;&#xA;if (this.viewMode === &#39;study&#39;) {&#xA;this.saveProgressSilent();&#xA;}&#xA;}&#xA;}&#xA;prevCard() {&#xA;if (this.currentIndex &gt; 0) {&#xA;this.currentIndex--;&#xA;this.updateCard();&#xA;&#xA;if (this.viewMode === &#39;study&#39;) {&#xA;this.saveProgressSilent();&#xA;}&#xA;}&#xA;}&#xA;changeStudyMode(mode) {&#xA;this.studyMode = mode;&#xA;this.updateCard();&#xA;&#xA;this.saveProgressSilent();&#xA;}&#xA;&#xA;showCompletionMessage() {&#xA;this.viewMode = &#39;browse&#39;;&#xA;this.updateModeButton(&#39;📖 Browsing&#39;, &#39;btn-secondary&#39;);&#xA;const nextReview = this.getNextReviewTime();&#xA;const allEarly = this.getDueCards(true);&#xA;const dueNow = this.getDueCards(false);&#xA;const earlyCards = allEarly.length - dueNow.length;&#xA;let message = &#34;You&#39;ve reviewed all due cards!&#34;;&#xA;if (nextReview) {&#xA;const timeUntil = nextReview - Date.now();&#xA;const hoursUntil = Math.ceil(timeUntil / (1000 * 60 * 60));&#xA;const daysUntil = Math.ceil(timeUntil / (1000 * 60 * 60 * 24));&#xA;if (hoursUntil &lt; 24) {&#xA;message += ` Next cards will be ready in about ${hoursUntil} hour${hoursUntil !== 1 ? &#39;s&#39; : &#39;&#39;}.`;&#xA;} else {&#xA;message += ` Next cards will be ready in about ${daysUntil} day${daysUntil !== 1 ? &#39;s&#39; : &#39;&#39;}.`;&#xA;}&#xA;}&#xA;this.elements.completionText.textContent = message;&#xA;if (earlyCards &gt; 0) {&#xA;this.elements.earlyReviewOption.style.display = &#39;inline-block&#39;;&#xA;this.elements.earlyReviewOption.textContent = `⏰ Review ${earlyCards} Early Card${earlyCards !== 1 ? &#39;s&#39; : &#39;&#39;}`;&#xA;} else {&#xA;this.elements.earlyReviewOption.style.display = &#39;none&#39;;&#xA;}&#xA;this.elements.completionMessage.style.display = &#39;flex&#39;;&#xA;this.saveProgressSilent();&#xA;}&#xA;getNextReviewTime() {&#xA;const now = Date.now();&#xA;let earliest = null;&#xA;for (let i = 0; i &lt; this.flashcards.length; i++) {&#xA;const card = this.cardData[i];&#xA;if (card &amp;&amp; card.nextReview &amp;&amp; card.nextReview &gt; now) {&#xA;if (!earliest || card.nextReview &lt; earliest) {&#xA;earliest = card.nextReview;&#xA;}&#xA;}&#xA;}&#xA;return earliest;&#xA;}&#xA;&#xA;resetProgress() {&#xA;this.cardData = {};&#xA;this.sessionStats = { reviewed: 0 };&#xA;this.reviewedInSession = new Set();&#xA;this.viewMode = &#39;browse&#39;;&#xA;this.cardOrder = [...Array(this.flashcards.length).keys()];&#xA;this.currentIndex = 0;&#xA;this.updateDisplay();&#xA;this.saveProgressSilent();&#xA;}&#xA;&#xA;initializeSession() {&#xA;if (this.viewMode === &#39;study&#39;) {&#xA;const dueCards = this.getDueCards();&#xA;if (dueCards.length &gt; 0) {&#xA;&#xA;this.cardOrder = this.shuffleArray(dueCards);&#xA;this.currentIndex = 0;&#xA;this.updateModeButton(&#39;📚 Studying&#39;, &#39;btn-primary&#39;);&#xA;} else {&#xA;this.viewMode = &#39;browse&#39;;&#xA;this.cardOrder = [...Array(this.flashcards.length).keys()];&#xA;this.currentIndex = Math.min(this.currentIndex, this.cardOrder.length - 1);&#xA;this.updateModeButton(&#39;📖 Browsing&#39;, &#39;btn-secondary&#39;);&#xA;}&#xA;} else {&#xA;&#xA;this.cardOrder = [...Array(this.flashcards.length).keys()];&#xA;this.currentIndex = Math.min(this.currentIndex, this.cardOrder.length - 1);&#xA;this.updateModeButton(&#39;📖 Browsing&#39;, &#39;btn-secondary&#39;);&#xA;}&#xA;}&#xA;&#xA;async saveProgress() {&#xA;this.saveToLocalStorage();&#xA;try {&#xA;const { data: { session }, error } = await supabaseClient.auth.getSession();&#xA;if (error || !session?.user?.id) {&#xA;return;&#xA;}&#xA;const progressData = {&#xA;user_id: session.user.id,&#xA;set_id: this.setId,&#xA;set_title: this.setTitle,&#xA;card_data: {&#xA;cardOrder: this.cardOrder,&#xA;currentIndex: this.currentIndex,&#xA;studyMode: this.studyMode,&#xA;viewMode: this.viewMode,&#xA;cardData: this.cardData&#xA;},&#xA;stats: this.sessionStats,&#xA;updated_at: new Date().toISOString()&#xA;};&#xA;const { error: saveError } = await supabaseClient&#xA;.from(&#39;flashcard_progress&#39;)&#xA;.upsert(progressData, { onConflict: &#39;user_id,set_id&#39; });&#xA;if (saveError) {&#xA;console.error(&#39;Supabase save error:&#39;, saveError);&#xA;}&#xA;} catch (e) {&#xA;console.error(&#39;Error saving progress:&#39;, e);&#xA;}&#xA;}&#xA;&#xA;async saveProgressSilent() {&#xA;this.saveToLocalStorage();&#xA;try {&#xA;const { data: { session }, error } = await supabaseClient.auth.getSession();&#xA;if (error || !session?.user?.id) {&#xA;return;&#xA;}&#xA;const progressData = {&#xA;user_id: session.user.id,&#xA;set_id: this.setId,&#xA;set_title: this.setTitle,&#xA;card_data: {&#xA;cardOrder: this.cardOrder,&#xA;currentIndex: this.currentIndex,&#xA;studyMode: this.studyMode,&#xA;viewMode: this.viewMode,&#xA;cardData: this.cardData&#xA;},&#xA;stats: this.sessionStats,&#xA;updated_at: new Date().toISOString()&#xA;};&#xA;await supabaseClient&#xA;.from(&#39;flashcard_progress&#39;)&#xA;.upsert(progressData, { onConflict: &#39;user_id,set_id&#39; });&#xA;} catch (e) {&#xA;console.error(&#39;Error saving progress silently:&#39;, e);&#xA;}&#xA;}&#xA;async loadProgress() {&#xA;&#xA;this.cardData = {};&#xA;this.sessionStats = { reviewed: 0 };&#xA;this.reviewedInSession = new Set();&#xA;try {&#xA;const { data: { session }, error } = await supabaseClient.auth.getSession();&#xA;if (error || !session?.user?.id) {&#xA;this.loadFromLocalStorage();&#xA;return;&#xA;}&#xA;const { data, error: dbError } = await supabaseClient&#xA;.from(&#39;flashcard_progress&#39;)&#xA;.select(&#39;*&#39;)&#xA;.eq(&#39;user_id&#39;, session.user.id)&#xA;.eq(&#39;set_id&#39;, this.setId)&#xA;.single();&#xA;if (dbError &amp;&amp; dbError.code !== &#39;PGRST116&#39;) {&#xA;console.error(&#39;Database error:&#39;, dbError);&#xA;this.loadFromLocalStorage();&#xA;return;&#xA;}&#xA;if (data) {&#xA;this.loadFromData(data);&#xA;&#xA;await this.migrateLocalStorageIfNewer(data.updated_at);&#xA;} else {&#xA;this.loadFromLocalStorage();&#xA;if (session?.user) {&#xA;await this.saveProgressSilent();&#xA;}&#xA;}&#xA;} catch (e) {&#xA;console.error(&#39;Error loading progress:&#39;, e);&#xA;this.loadFromLocalStorage();&#xA;}&#xA;}&#xA;&#xA;loadFromData(data) {&#xA;if (data.card_data) {&#xA;this.cardOrder = this.validateArray(data.card_data.cardOrder, this.flashcards.length) ||&#xA;[...Array(this.flashcards.length).keys()];&#xA;this.cardData = this.validateCardData(data.card_data.cardData) || {};&#xA;this.currentIndex = Math.max(0, Math.min(data.card_data.currentIndex || 0, this.cardOrder.length - 1));&#xA;this.studyMode = [&#39;term-to-definition&#39;, &#39;definition-to-term&#39;].includes(data.card_data.studyMode) ?&#xA;data.card_data.studyMode : &#39;term-to-definition&#39;;&#xA;this.viewMode = [&#39;browse&#39;, &#39;study&#39;].includes(data.card_data.viewMode) ?&#xA;data.card_data.viewMode : &#39;browse&#39;;&#xA;}&#xA;if (data.stats &amp;&amp; typeof data.stats === &#39;object&#39;) {&#xA;this.sessionStats = {&#xA;reviewed: data.stats.reviewed || 0&#xA;};&#xA;}&#xA;}&#xA;loadFromLocalStorage() {&#xA;const storageKey = `flashcards_${this.setId}`;&#xA;const saved = localStorage.getItem(storageKey);&#xA;if (saved) {&#xA;try {&#xA;const data = JSON.parse(saved);&#xA;this.loadFromData({&#xA;card_data: {&#xA;cardOrder: data.cardOrder,&#xA;cardData: data.cardData,&#xA;currentIndex: data.currentIndex,&#xA;studyMode: data.studyMode,&#xA;viewMode: data.viewMode&#xA;},&#xA;stats: data.sessionStats&#xA;});&#xA;} catch (e) {&#xA;console.error(&#39;Error parsing localStorage:&#39;, e);&#xA;}&#xA;}&#xA;}&#xA;async migrateLocalStorageIfNewer(dbUpdatedAt) {&#xA;const storageKey = `flashcards_${this.setId}`;&#xA;const saved = localStorage.getItem(storageKey);&#xA;if (!saved) return;&#xA;try {&#xA;const localData = JSON.parse(saved);&#xA;const localUpdated = new Date(localData.lastUpdated || 0);&#xA;const dbUpdated = new Date(dbUpdatedAt);&#xA;if (localUpdated &gt; dbUpdated) {&#xA;this.loadFromData({&#xA;card_data: {&#xA;cardOrder: localData.cardOrder,&#xA;cardData: localData.cardData,&#xA;currentIndex: localData.currentIndex,&#xA;studyMode: localData.studyMode,&#xA;viewMode: localData.viewMode&#xA;},&#xA;stats: localData.sessionStats&#xA;});&#xA;await this.saveProgressSilent();&#xA;}&#xA;} catch (e) {&#xA;console.error(&#39;Error during migration:&#39;, e);&#xA;}&#xA;}&#xA;saveToLocalStorage() {&#xA;const storageKey = `flashcards_${this.setId}`;&#xA;const data = {&#xA;cardOrder: this.cardOrder,&#xA;currentIndex: this.currentIndex,&#xA;studyMode: this.studyMode,&#xA;viewMode: this.viewMode,&#xA;cardData: this.cardData,&#xA;sessionStats: this.sessionStats,&#xA;lastUpdated: new Date().toISOString(),&#xA;setTitle: this.setTitle&#xA;};&#xA;try {&#xA;localStorage.setItem(storageKey, JSON.stringify(data));&#xA;} catch (e) {&#xA;console.error(&#39;Error saving to localStorage:&#39;, e);&#xA;}&#xA;}&#xA;&#xA;validateArray(arr, expectedLength) {&#xA;if (!Array.isArray(arr) || arr.length !== expectedLength) return null;&#xA;return arr.every(idx =&gt; Number.isInteger(idx) &amp;&amp; idx &gt;= 0 &amp;&amp; idx &lt; expectedLength) ? arr : null;&#xA;}&#xA;validateCardData(data) {&#xA;if (!data || typeof data !== &#39;object&#39;) return null;&#xA;const validated = {};&#xA;for (const [key, value] of Object.entries(data)) {&#xA;if (value &amp;&amp; typeof value === &#39;object&#39; &amp;&amp;&#xA;typeof value.interval === &#39;number&#39; &amp;&amp;&#xA;typeof value.easeFactor === &#39;number&#39;) {&#xA;validated[key] = value;&#xA;}&#xA;}&#xA;return validated;&#xA;}&#xA;}&#xA;&#xA;document.addEventListener(&#39;DOMContentLoaded&#39;, () =&gt; {&#xA;updateAuthLink();&#xA;window.flashcardSystem = new FlashcardSystem();&#xA;});&#xA;&#xA;supabaseClient.auth.onAuthStateChange(async (event, session) =&gt; {&#xA;console.log(&#39;Auth state changed:&#39;, event);&#xA;updateAuthLink();&#xA;&#xA;});&#xA;&#xA;window.addEventListener(&#39;focus&#39;, () =&gt; {&#xA;setTimeout(updateAuthLink, 1000); &#xA;});&#xA;&lt;/script&gt;</description>
      
    </item>
    
    <item>
      <title>Flashcards</title>
      <link>https://premieres.stephanejacquet.fr/chapters/women_detectives/flashcards/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      
      <guid>https://premieres.stephanejacquet.fr/chapters/women_detectives/flashcards/</guid>
      <description>&lt;div class=&#34;flashcards-container&#34;&gt;&#xA;&lt;div style=&#34;display:flex; justify-content:space-between; align-items:baseline; gap:1rem; flex-wrap:wrap;&#34;&gt;&#xA;&lt;h2&gt;🧠 Women Detectives &amp;mdash; Flashcards&lt;/h2&gt;&#xA;&lt;a href=&#34;https://premieres.stephanejacquet.fr/login/&#34; id=&#34;auth-link&#34; class=&#34;login-link&#34; style=&#34;color:#007bff; text-decoration:none; font-size:0.9rem; white-space:nowrap;&#34;&gt;Login&lt;/a&gt;&#xA;&lt;/div&gt;&#xA;&lt;div class=&#34;flashcards-header&#34;&gt;&#xA;&lt;div class=&#34;flashcards-controls&#34;&gt;&#xA;&lt;div class=&#34;mode-selector&#34;&gt;&#xA;&lt;label class=&#34;mode-option&#34;&gt;&#xA;&lt;input type=&#34;radio&#34; name=&#34;study-mode&#34; value=&#34;term-to-definition&#34; checked&gt;&#xA;&lt;span&gt;Term → Definition&lt;/span&gt;&#xA;&lt;/label&gt;&#xA;&lt;label class=&#34;mode-option&#34;&gt;&#xA;&lt;input type=&#34;radio&#34; name=&#34;study-mode&#34; value=&#34;definition-to-term&#34;&gt;&#xA;&lt;span&gt;Definition → Term&lt;/span&gt;&#xA;&lt;/label&gt;&#xA;&lt;/div&gt;&#xA;&lt;div class=&#34;control-buttons&#34;&gt;&#xA;&lt;button id=&#34;mode-toggle-btn&#34; class=&#34;btn btn-secondary&#34;&gt;📖 Browse&lt;/button&gt;&#xA;&lt;button id=&#34;early-review-btn&#34; class=&#34;btn btn-info&#34;&gt;⏰ Early Review&lt;/button&gt;&#xA;&lt;button id=&#34;reset-progress&#34; class=&#34;btn btn-outline&#34;&gt;🔄 Reset&lt;/button&gt;&#xA;&lt;/div&gt;&#xA;&lt;div class=&#34;progress-display&#34;&gt;&#xA;&lt;span id=&#34;current-card&#34;&gt;1&lt;/span&gt; / &lt;span id=&#34;total-cards&#34;&gt;24&lt;/span&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&#xA;&lt;div class=&#34;flashcard-wrapper&#34;&gt;&#xA;&lt;div class=&#34;flashcard&#34; id=&#34;flashcard&#34;&gt;&#xA;&lt;div class=&#34;flashcard-inner&#34;&gt;&#xA;&lt;div class=&#34;flashcard-front&#34;&gt;&#xA;&lt;div class=&#34;card-content&#34;&gt;&#xA;&lt;div class=&#34;question&#34; id=&#34;card-question&#34;&gt;&lt;/div&gt;&#xA;&lt;div class=&#34;card-hint&#34;&gt;Tap to reveal answer&lt;/div&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&#xA;&lt;div class=&#34;flashcard-back&#34;&gt;&#xA;&lt;div class=&#34;card-content&#34;&gt;&#xA;&lt;div class=&#34;question-small&#34; id=&#34;card-question-back&#34;&gt;&lt;/div&gt;&#xA;&lt;div class=&#34;answer&#34; id=&#34;card-answer&#34;&gt;&lt;/div&gt;&#xA;&lt;div class=&#34;card-hint&#34;&gt;Tap to flip back&lt;/div&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&#xA;&lt;div class=&#34;flashcards-navigation&#34;&gt;&#xA;&lt;div class=&#34;nav-top&#34;&gt;&#xA;&lt;button id=&#34;next-btn&#34; class=&#34;btn btn-primary&#34;&gt;Next →&lt;/button&gt;&#xA;&lt;/div&gt;&#xA;&lt;div class=&#34;nav-middle&#34;&gt;&#xA;&lt;div class=&#34;difficulty-buttons&#34;&gt;&#xA;&lt;button id=&#34;again-btn&#34; class=&#34;btn btn-danger-dark&#34;&gt;🚫 Again&lt;/button&gt;&#xA;&lt;button id=&#34;hard-btn&#34; class=&#34;btn btn-danger&#34;&gt;😰 Hard&lt;/button&gt;&#xA;&lt;button id=&#34;medium-btn&#34; class=&#34;btn btn-warning&#34;&gt;🤔 Medium&lt;/button&gt;&#xA;&lt;button id=&#34;easy-btn&#34; class=&#34;btn btn-success&#34;&gt;😊 Easy&lt;/button&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&#xA;&lt;div class=&#34;nav-bottom&#34;&gt;&#xA;&lt;button id=&#34;prev-btn&#34; class=&#34;btn btn-primary&#34;&gt;← Previous&lt;/button&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&#xA;&lt;div class=&#34;progress-stats&#34;&gt;&#xA;&lt;div class=&#34;stat&#34;&gt;&#xA;&lt;span class=&#34;stat-label&#34;&gt;Reviewed:&lt;/span&gt;&#xA;&lt;span id=&#34;reviewed-count&#34;&gt;0&lt;/span&gt;&#xA;&lt;/div&gt;&#xA;&lt;div class=&#34;stat&#34;&gt;&#xA;&lt;span class=&#34;stat-label&#34;&gt;Again:&lt;/span&gt;&#xA;&lt;span id=&#34;again-count&#34;&gt;0&lt;/span&gt;&#xA;&lt;/div&gt;&#xA;&lt;div class=&#34;stat&#34;&gt;&#xA;&lt;span class=&#34;stat-label&#34;&gt;Hard:&lt;/span&gt;&#xA;&lt;span id=&#34;hard-count&#34;&gt;0&lt;/span&gt;&#xA;&lt;/div&gt;&#xA;&lt;div class=&#34;stat&#34;&gt;&#xA;&lt;span class=&#34;stat-label&#34;&gt;Medium:&lt;/span&gt;&#xA;&lt;span id=&#34;medium-count&#34;&gt;0&lt;/span&gt;&#xA;&lt;/div&gt;&#xA;&lt;div class=&#34;stat&#34;&gt;&#xA;&lt;span class=&#34;stat-label&#34;&gt;Easy:&lt;/span&gt;&#xA;&lt;span id=&#34;easy-count&#34;&gt;0&lt;/span&gt;&#xA;&lt;/div&gt;&#xA;&lt;div class=&#34;stat&#34;&gt;&#xA;&lt;span class=&#34;stat-label&#34;&gt;Due:&lt;/span&gt;&#xA;&lt;span id=&#34;review-count&#34;&gt;0&lt;/span&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&#xA;&lt;div class=&#34;completion-message&#34; id=&#34;completion-message&#34; style=&#34;display: none;&#34;&gt;&#xA;&lt;div class=&#34;completion-content&#34;&gt;&#xA;&lt;div class=&#34;completion-icon&#34;&gt;🎉&lt;/div&gt;&#xA;&lt;h3 class=&#34;completion-title&#34;&gt;Great Job!&lt;/h3&gt;&#xA;&lt;p class=&#34;completion-text&#34; id=&#34;completion-text&#34;&gt;&lt;/p&gt;&#xA;&lt;div class=&#34;completion-actions&#34;&gt;&#xA;&lt;button id=&#34;early-review-option&#34; class=&#34;btn btn-info&#34; style=&#34;display: none;&#34;&gt;⏰ Review Early Cards&lt;/button&gt;&#xA;&lt;button id=&#34;browse-all-option&#34; class=&#34;btn btn-secondary&#34;&gt;📖 Browse All Cards&lt;/button&gt;&#xA;&lt;button id=&#34;close-completion&#34; class=&#34;btn btn-primary&#34;&gt;✨ Done&lt;/button&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&#xA;&lt;style&gt;&#xA; &#xA;.stressed-vowel {&#xA;color: red !important;&#xA;font-weight: bold;&#xA;}&#xA; &#xA;.btn-danger-dark {&#xA;background: #8b0000;&#xA;color: white;&#xA;}&#xA;.btn-danger-dark:hover {&#xA;background: #a00000;&#xA;transform: translateY(-1px);&#xA;box-shadow: 0 2px 8px rgba(0,0,0,0.2);&#xA;}&#xA; &#xA;.flashcards-container {&#xA;max-width: 600px;&#xA;margin: 0 auto;&#xA;padding: 1rem;&#xA;font-family: -apple-system, BlinkMacSystemFont, &#39;Segoe UI&#39;, Roboto, sans-serif;&#xA;display: flex;&#xA;flex-direction: column;&#xA;box-sizing: border-box;&#xA;gap: 1rem;&#xA;}&#xA;.flashcards-header {&#xA;display: flex;&#xA;justify-content: space-between;&#xA;align-items: center;&#xA;margin-bottom: 1rem;&#xA;flex-wrap: wrap;&#xA;gap: 1rem;&#xA;}&#xA;.flashcards-header h3 {&#xA;margin: 0;&#xA;color: inherit;&#xA;font-size: clamp(1.2rem, 4vw, 1.5rem);&#xA;}&#xA;.flashcards-controls {&#xA;display: flex;&#xA;align-items: center;&#xA;gap: 1.2rem;&#xA;flex-wrap: wrap;&#xA;padding: 0.5rem 0;&#xA;}&#xA;.mode-selector {&#xA;display: flex;&#xA;gap: 0.8rem;&#xA;align-items: center;&#xA;}&#xA;.mode-option {&#xA;display: flex;&#xA;align-items: center;&#xA;gap: 0.5rem;&#xA;cursor: pointer;&#xA;padding: 0.5rem 0.75rem;&#xA;border-radius: 20px;&#xA;background: #f8f9fa;&#xA;border: 1px solid #ced4da;&#xA;color: #212529;&#xA;transition: all 0.2s ease;&#xA;font-size: clamp(0.75rem, 3vw, 0.9rem);&#xA;white-space: nowrap;&#xA;}&#xA;.mode-option span {&#xA;color: #212529;&#xA;}&#xA;.mode-option:hover {&#xA;background: #e9ecef;&#xA;}&#xA;.mode-option input[type=&#34;radio&#34;] {&#xA;margin: 0;&#xA;}&#xA;.mode-option input[type=&#34;radio&#34;]:checked + span {&#xA;font-weight: bold;&#xA;color: #007bff;&#xA;}&#xA;.control-buttons {&#xA;display: flex;&#xA;gap: 0.8rem;&#xA;}&#xA;.progress-display {&#xA;background: #f5f5f5;&#xA;padding: 0.5rem 0.75rem;&#xA;border-radius: 20px;&#xA;border: 1px solid #ced4da;&#xA;font-weight: bold;&#xA;color: #212529;&#xA;font-size: clamp(0.8rem, 3vw, 0.9rem);&#xA;}&#xA;.flashcard-wrapper {&#xA;perspective: 1000px;&#xA;margin: 1.5rem 0;&#xA;display: flex;&#xA;align-items: center;&#xA;}&#xA;.flashcard {&#xA;width: 100%;&#xA;height: clamp(220px, 35vh, 320px);&#xA;position: relative;&#xA;cursor: pointer;&#xA;transition: transform 0.3s ease;&#xA;}&#xA;.flashcard:hover {&#xA;transform: translateY(-2px);&#xA;}&#xA;.flashcard-inner {&#xA;position: relative;&#xA;width: 100%;&#xA;height: 100%;&#xA;text-align: center;&#xA;transition: transform 0.6s;&#xA;transform-style: preserve-3d;&#xA;}&#xA;.flashcard.flipped .flashcard-inner {&#xA;transform: rotateY(180deg);&#xA;}&#xA;.flashcard-front, .flashcard-back {&#xA;position: absolute;&#xA;width: 100%;&#xA;height: 100%;&#xA;backface-visibility: hidden;&#xA;border-radius: 15px;&#xA;box-shadow: 0 4px 20px rgba(0,0,0,0.1);&#xA;display: flex;&#xA;align-items: center;&#xA;justify-content: center;&#xA;}&#xA;.flashcard-front {&#xA;background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);&#xA;color: white;&#xA;}&#xA;.flashcard-back {&#xA;background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);&#xA;color: white;&#xA;transform: rotateY(180deg);&#xA;}&#xA;.card-content {&#xA;padding: clamp(1.5rem, 5vw, 2.5rem);&#xA;width: 100%;&#xA;height: 100%;&#xA;display: flex;&#xA;flex-direction: column;&#xA;justify-content: center;&#xA;box-sizing: border-box;&#xA;overflow: hidden;&#xA;}&#xA;&#xA; &#xA;.term, .question {&#xA;    font-size: clamp(1.4rem, 5vw, 2rem);&#xA;    font-weight: bold;&#xA;    margin-bottom: 1rem;&#xA;    text-shadow: 0 2px 4px rgba(0,0,0,0.3);&#xA;    line-height: 1.3;&#xA;    overflow-wrap: break-word;&#xA;    hyphens: auto;&#xA;    display: flex;&#xA;    align-items: center;&#xA;    justify-content: center;&#xA;    text-align: center;&#xA;    height: 100%;&#xA;    margin: 0 auto;&#xA;     &#xA;    white-space: pre-wrap;&#xA;}&#xA;&#xA;&#xA;&#xA;&#xA;&#xA;&#xA;&#xA;.term-small, .question-small {&#xA;font-size: clamp(0.85rem, 3.2vw, 1.1rem);&#xA;font-weight: bold;&#xA;margin-bottom: 0.75rem;&#xA;opacity: 0.8;&#xA;line-height: 1.3;&#xA;overflow-wrap: break-word;&#xA;text-align: center;&#xA;}&#xA;.definition, .answer {&#xA;font-size: clamp(1.4rem, 5vw, 2rem);&#xA;font-weight: bold;&#xA;margin-bottom: 1rem;&#xA;text-shadow: 0 2px 4px rgba(0,0,0,0.3);&#xA;line-height: 1.3;&#xA;overflow-wrap: break-word;&#xA;hyphens: auto;&#xA;flex: 1;&#xA;display: flex;&#xA;align-items: center;&#xA;justify-content: center;&#xA;text-align: center;&#xA;}&#xA;.card-hint {&#xA;font-size: clamp(0.7rem, 2.3vw, 0.85rem);&#xA;opacity: 0.7;&#xA;font-style: italic;&#xA;margin-top: auto;&#xA;text-align: center;&#xA;}&#xA;.flashcards-navigation {&#xA;display: flex;&#xA;flex-direction: column;&#xA;gap: 0.75rem;&#xA;margin: 1.5rem 0;&#xA;}&#xA;.nav-top, .nav-bottom {&#xA;display: flex;&#xA;justify-content: center;&#xA;}&#xA;.nav-middle {&#xA;display: flex;&#xA;justify-content: center;&#xA;}&#xA;.difficulty-buttons {&#xA;display: flex;&#xA;gap: 0.8rem;&#xA;justify-content: center;&#xA;flex-wrap: wrap;&#xA;}&#xA;.btn {&#xA;padding: clamp(0.4rem, 1.8vw, 0.6rem) clamp(0.8rem, 2.5vw, 1rem);&#xA;border: none;&#xA;border-radius: 8px;&#xA;cursor: pointer;&#xA;font-weight: 500;&#xA;transition: all 0.2s ease;&#xA;font-size: clamp(0.75rem, 2.8vw, 0.85rem);&#xA;white-space: nowrap;&#xA;min-width: fit-content;&#xA;}&#xA;.btn:hover {&#xA;transform: translateY(-1px);&#xA;box-shadow: 0 2px 8px rgba(0,0,0,0.2);&#xA;}&#xA;.btn-primary { background: #007bff; color: white; }&#xA;.btn-secondary { background: #6c757d; color: white; }&#xA;.btn-secondary:hover { background: #5a6268; }&#xA;.btn-success { background: #28a745; color: white; }&#xA;.btn-warning { background: #ffc107; color: #212529; }&#xA;.btn-danger { background: #dc3545; color: white; }&#xA;.btn-outline { background: white; border: 2px solid #495057; color: #212529; }&#xA;.btn-outline:hover { background: #495057; color: white; }&#xA;.btn-info { background: #17a2b8; color: white; }&#xA;.btn-info:hover { background: #138496; }&#xA;.btn:disabled {&#xA;opacity: 0.5;&#xA;cursor: not-allowed;&#xA;transform: none;&#xA;}&#xA;.progress-stats {&#xA;display: grid;&#xA;grid-template-columns: repeat(auto-fit, minmax(70px, 1fr));&#xA;gap: 0.75rem;&#xA;background: #f8f9fa;&#xA;border: 1px solid #ced4da;&#xA;padding: 0.75rem;&#xA;border-radius: 10px;&#xA;margin-top: 1rem;&#xA;}&#xA;.stat {&#xA;text-align: center;&#xA;flex: 1;&#xA;min-width: 70px;&#xA;}&#xA;.stat-label {&#xA;display: block;&#xA;font-size: clamp(0.65rem, 2.3vw, 0.75rem);&#xA;color: #666;&#xA;text-transform: uppercase;&#xA;letter-spacing: 0.5px;&#xA;}&#xA;.stat span:last-child {&#xA;display: block;&#xA;font-size: clamp(1rem, 3.5vw, 1.3rem);&#xA;font-weight: bold;&#xA;color: #333;&#xA;margin-top: 0.25rem;&#xA;}&#xA;.completion-message {&#xA;position: fixed;&#xA;top: 0;&#xA;left: 0;&#xA;width: 100%;&#xA;height: 100%;&#xA;background: rgba(0, 0, 0, 0.8);&#xA;display: flex;&#xA;align-items: center;&#xA;justify-content: center;&#xA;z-index: 1000;&#xA;backdrop-filter: blur(5px);&#xA;}&#xA;.completion-content {&#xA;background: white;&#xA;padding: 2rem;&#xA;border-radius: 20px;&#xA;text-align: center;&#xA;max-width: 90%;&#xA;max-height: 90%;&#xA;overflow-y: auto;&#xA;box-shadow: 0 20px 40px rgba(0, 0, 0, 0.3);&#xA;animation: completionSlideIn 0.3s ease-out;&#xA;}&#xA;@keyframes completionSlideIn {&#xA;from {&#xA;opacity: 0;&#xA;transform: translateY(-50px) scale(0.9);&#xA;}&#xA;to {&#xA;opacity: 1;&#xA;transform: translateY(0) scale(1);&#xA;}&#xA;}&#xA;.completion-icon {&#xA;font-size: 4rem;&#xA;margin-bottom: 1rem;&#xA;animation: bounce 1s ease-in-out infinite alternate;&#xA;}&#xA;@keyframes bounce {&#xA;from { transform: translateY(0); }&#xA;to { transform: translateY(-10px); }&#xA;}&#xA;.completion-title {&#xA;color: #333;&#xA;margin-bottom: 1rem;&#xA;font-size: 2rem;&#xA;font-weight: bold;&#xA;}&#xA;.completion-text {&#xA;color: #666;&#xA;margin-bottom: 2rem;&#xA;font-size: 1.1rem;&#xA;line-height: 1.5;&#xA;}&#xA;.completion-actions {&#xA;display: flex;&#xA;gap: 1rem;&#xA;justify-content: center;&#xA;flex-wrap: wrap;&#xA;}&#xA;.completion-actions .btn {&#xA;min-width: 120px;&#xA;}&#xA; &#xA;@media (max-width: 768px) {&#xA;.flashcards-container { padding: 0.75rem; gap: 0.75rem; }&#xA;.flashcards-header { flex-direction: column; align-items: flex-start; margin-bottom: 0.75rem; gap: 0.75rem; }&#xA;.flashcards-controls { flex-direction: column; align-items: flex-start; gap: 0.75rem; width: 100%; }&#xA;.mode-selector { width: 100%; justify-content: flex-start; }&#xA;.control-buttons { width: 100%; justify-content: flex-start; }&#xA;.progress-display { align-self: flex-start; }&#xA;.flashcard { height: clamp(180px, 30vh, 250px); }&#xA;.flashcard-wrapper { margin: 1rem 0; }&#xA;.flashcards-navigation { margin: 1rem 0; gap: 0.5rem; }&#xA;.card-content { padding: clamp(1.2rem, 4vw, 2rem); }&#xA;.difficulty-buttons { gap: 0.5rem; }&#xA;.progress-stats { grid-template-columns: repeat(3, 1fr); gap: 0.5rem; }&#xA;}&#xA;@media (max-width: 480px) {&#xA;.flashcards-container { padding: 0.5rem; }&#xA;.flashcard { height: clamp(150px, 28vh, 220px); }&#xA;.flashcard-wrapper { margin: 0.75rem 0; }&#xA;.flashcards-navigation { margin: 0.75rem 0; }&#xA;.card-content { padding: clamp(1rem, 3.5vw, 1.5rem); }&#xA;.completion-content { padding: 1.5rem; margin: 1rem; }&#xA;.completion-icon { font-size: 3rem; }&#xA;.completion-title { font-size: 1.5rem; }&#xA;.completion-text { font-size: 1rem; }&#xA;.completion-actions { flex-direction: column; align-items: center; }&#xA;.completion-actions .btn { width: 100%; max-width: 200px; }&#xA;.progress-stats { grid-template-columns: repeat(2, 1fr); }&#xA;.difficulty-buttons { flex-wrap: wrap; gap: 0.3rem; }&#xA;.difficulty-buttons .btn { flex: 1; min-width: 60px; font-size: 0.7rem; padding: 0.3rem 0.5rem; }&#xA; &#xA;.difficulty-buttons .btn { text-indent: -1ch; overflow: hidden; white-space: nowrap; }&#xA;}&#xA;@media (max-height: 500px) and (orientation: landscape) {&#xA;.flashcard { height: clamp(120px, 45vh, 180px); }&#xA;.flashcard-wrapper { margin: 0.5rem 0; }&#xA;.flashcards-navigation { margin: 0.5rem 0; gap: 0.3rem; }&#xA;.flashcards-header h3 { font-size: 1rem; }&#xA;.progress-stats { padding: 0.5rem; }&#xA;.card-content { padding: clamp(0.8rem, 3vw, 1.2rem); }&#xA;}&#xA;&lt;/style&gt;&#xA;&lt;script src=&#34;https://unpkg.com/@supabase/supabase-js@2&#34;&gt;&lt;/script&gt;&#xA;&lt;script&gt;&#xA;&#xA;const { createClient } = supabase;&#xA;const supabaseClient = createClient(&#xA;&#39;https://xjurrqzjvhzjweufgivl.supabase.co&#39;,&#xA;&#39;eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6InhqdXJycXpqdmh6andldWZnaXZsIiwicm9sZSI6ImFub24iLCJpYXQiOjE3NDg5NDUzMTIsImV4cCI6MjA2NDUyMTMxMn0.rimZk-g9-RmvQCbQJ5Phk0lKwOue6pPlgibO-LKHqmM&#39;&#xA;);&#xA;&#xA;let authCheckInProgress = false;&#xA;let lastAuthCheck = 0;&#xA;const AUTH_CHECK_THROTTLE = 5000; &#xA;async function updateAuthLink() {&#xA;const now = Date.now();&#xA;if (authCheckInProgress || (now - lastAuthCheck) &lt; AUTH_CHECK_THROTTLE) {&#xA;return; &#xA;}&#xA;authCheckInProgress = true;&#xA;lastAuthCheck = now;&#xA;const authLink = document.getElementById(&#39;auth-link&#39;);&#xA;if (!authLink) {&#xA;authCheckInProgress = false;&#xA;return;&#xA;}&#xA;try {&#xA;const { data: { session }, error } = await supabaseClient.auth.getSession();&#xA;if (error || !session?.user) {&#xA;authLink.textContent = &#39;Login&#39;;&#xA;authLink.href = &#39;/login/&#39;;&#xA;authLink.onclick = null;&#xA;return;&#xA;}&#xA;authLink.textContent = &#39;Logout&#39;;&#xA;authLink.onclick = async function(e) {&#xA;e.preventDefault();&#xA;try {&#xA;await supabaseClient.auth.signOut();&#xA;window.location.reload();&#xA;} catch (err) {&#xA;window.location.reload();&#xA;}&#xA;};&#xA;} catch (err) {&#xA;authLink.textContent = &#39;Login&#39;;&#xA;authLink.href = &#39;/login/&#39;;&#xA;authLink.onclick = null;&#xA;} finally {&#xA;authCheckInProgress = false;&#xA;}&#xA;}&#xA;&#xA;class FlashcardSystem {&#xA;constructor() {&#xA;&#xA;this.flashcards = [&#xA;&#xA;&#xA;{&#xA;term: &#34;\&#34;investigation\&#34;&#34;,&#xA;definition: &#34;\&#34;enquiry\&#34;&#34;,&#xA;stressed: &#34;\&#34;inv*estig*ation\&#34;&#34;,&#xA;id: &#34;\&#34;8f7825f0bc502bfe1d601af4599fd586590126281b524ef2c96599aa43a54a80\&#34;&#34;&#xA;},&#xA;&#xA;&#xA;&#xA;{&#xA;term: &#34;\&#34;evidence\&#34;&#34;,&#xA;definition: &#34;\&#34;proof\&#34;&#34;,&#xA;stressed: &#34;\&#34;*evidence\&#34;&#34;,&#xA;id: &#34;\&#34;d0d99b2ff3a64c5ad50422236a5a6950d34fe0ddf494c1b1ecf4456ddd012a9f\&#34;&#34;&#xA;},&#xA;&#xA;&#xA;&#xA;{&#xA;term: &#34;\&#34;professional\&#34;&#34;,&#xA;definition: &#34;\&#34;≠ amateur\&#34;&#34;,&#xA;stressed: &#34;\&#34;prof*essional\&#34;&#34;,&#xA;id: &#34;\&#34;3ed080e82ed40f3406e773625e030bf932bfafd17eb5c16cc03db8a254213cbc\&#34;&#34;&#xA;},&#xA;&#xA;&#xA;&#xA;{&#xA;term: &#34;\&#34;active\&#34;&#34;,&#xA;definition: &#34;\&#34;≠ passive\&#34;&#34;,&#xA;stressed: &#34;\&#34;*active\&#34;&#34;,&#xA;id: &#34;\&#34;7e9bd8334dde41982a10ad35dfaa5af1e7374e3bdf56117b68056d2a5df6a87b\&#34;&#34;&#xA;},&#xA;&#xA;&#xA;&#xA;{&#xA;term: &#34;\&#34;traditional\&#34;&#34;,&#xA;definition: &#34;\&#34;≠ modern\&#34;&#34;,&#xA;stressed: &#34;\&#34;trad*itional\&#34;&#34;,&#xA;id: &#34;\&#34;b0ed8930796aec42842167a30fe2ded52606ae4f94c8139f67b4545d0025e280\&#34;&#34;&#xA;},&#xA;&#xA;&#xA;&#xA;{&#xA;term: &#34;\&#34;unconventional\&#34;&#34;,&#xA;definition: &#34;\&#34;unusual\&#34;&#34;,&#xA;stressed: &#34;\&#34;*unconv*entional\&#34;&#34;,&#xA;id: &#34;\&#34;308dd2a61f833a2435dc8baf1528ea73b96662d342220c06029a59d430d6ffab\&#34;&#34;&#xA;},&#xA;&#xA;&#xA;&#xA;{&#xA;term: &#34;\&#34;unfair\&#34;&#34;,&#xA;definition: &#34;\&#34;unjust\&#34;&#34;,&#xA;stressed: &#34;\&#34;unf*a*ir\&#34;&#34;,&#xA;id: &#34;\&#34;e6d59c229877a069019af4532c26865ba6ceab48a67fc35dfcada62fb6c0464c\&#34;&#34;&#xA;},&#xA;&#xA;&#xA;&#xA;{&#xA;term: &#34;\&#34;equal\&#34;&#34;,&#xA;definition: &#34;\&#34;≠ unequal\&#34;&#34;,&#xA;stressed: &#34;\&#34;*equal\&#34;&#34;,&#xA;id: &#34;\&#34;d428424a44abfa3c98dba717cd21a97667e4d0c7a6705176037f1e2fbb60b1c3\&#34;&#34;&#xA;},&#xA;&#xA;&#xA;&#xA;{&#xA;term: &#34;\&#34;determined\&#34;&#34;,&#xA;definition: &#34;\&#34;showing determination\&#34;&#34;,&#xA;stressed: &#34;\&#34;det*ermined\&#34;&#34;,&#xA;id: &#34;\&#34;03cd887e72c19fbca3f07573b3b54acf71ea3232651d4ebe5cc6e3bd01161ea5\&#34;&#34;&#xA;},&#xA;&#xA;&#xA;&#xA;{&#xA;term: &#34;\&#34;(to) gossip\&#34;&#34;,&#xA;definition: &#34;\&#34;(to) talk about other people&#39;s private business behind their back\&#34;&#34;,&#xA;stressed: &#34;\&#34;g*ossip\&#34;&#34;,&#xA;id: &#34;\&#34;96e0cad5ed468e5b57ed3309a5d6f9521910d03e8d64445da0474c7d36f36ad8\&#34;&#34;&#xA;},&#xA;&#xA;&#xA;&#xA;{&#xA;term: &#34;\&#34;gossip\&#34;&#34;,&#xA;definition: &#34;\&#34;une commmère\&#34;&#34;,&#xA;stressed: &#34;\&#34;g*ossip\&#34;&#34;,&#xA;id: &#34;\&#34;4019c974f9837b883ef12203ce5de159f8c05374dd108e4b5cc3b179c52e80e9\&#34;&#34;&#xA;},&#xA;&#xA;&#xA;&#xA;{&#xA;term: &#34;\&#34;cunning\&#34;&#34;,&#xA;definition: &#34;\&#34;clever\&#34;&#34;,&#xA;stressed: &#34;\&#34;c*unning\&#34;&#34;,&#xA;id: &#34;\&#34;126ff588a692e8b15e3da562c8923769c7ba3b696eaac9a28757abb6b24e2b4c\&#34;&#34;&#xA;},&#xA;&#xA;&#xA;&#xA;&#xA;&#xA;{&#xA;term: &#34;\&#34;insufferable\&#34;&#34;,&#xA;definition: &#34;\&#34;extremely annoying or unpleasant\&#34;&#34;,&#xA;stressed: &#34;\&#34;ins*ufferable\&#34;&#34;,&#xA;id: &#34;\&#34;664a3e00b4f6ac94530902313cc4255faa63bf2a372ef1be44ff5f065cae9791\&#34;&#34;&#xA;},&#xA;&#xA;&#xA;&#xA;{&#xA;term: &#34;\&#34;(to) miss\&#34;&#34;,&#xA;definition: &#34;\&#34;to not see, hear, or notice something\&#34;&#34;,&#xA;stressed: &#34;\&#34;(to) miss\&#34;&#34;,&#xA;id: &#34;\&#34;24698fe2744d2ec80f5a0983f6e037b80dcaa939eda29e518334ad021f1816dc\&#34;&#34;&#xA;},&#xA;&#xA;&#xA;&#xA;{&#xA;term: &#34;\&#34;(to) notice\&#34;&#34;,&#xA;definition: &#34;\&#34;if you notice something or someone, you realise they exist\&#34;&#34;,&#xA;stressed: &#34;\&#34;(to) n*otice\&#34;&#34;,&#xA;id: &#34;\&#34;de29f1e229ccc7bd43afc41355f07f772a094643ce430ca4467647722f58a684\&#34;&#34;&#xA;},&#xA;&#xA;&#xA;&#xA;{&#xA;term: &#34;\&#34;skill\&#34;&#34;,&#xA;definition: &#34;\&#34;the ability to do something well because you have learned or practised it\&#34;&#34;,&#xA;stressed: &#34;\&#34;skill\&#34;&#34;,&#xA;id: &#34;\&#34;f92e3f58111b185356bf3571e06e94b418fde53b335e08d0c5088262fe016509\&#34;&#34;&#xA;},&#xA;&#xA;&#xA;&#xA;{&#xA;term: &#34;\&#34;spinster\&#34;&#34;,&#xA;definition: &#34;\&#34;an unmarried women, usually one who is no longer young and seems unlikely to marry\&#34;&#34;,&#xA;stressed: &#34;\&#34;sp*inster\&#34;&#34;,&#xA;id: &#34;\&#34;1064359b16c2f437075a4e61117a337f3a05f1d9baf0ffd3ec1e835e17f52250\&#34;&#34;&#xA;},&#xA;&#xA;&#xA;&#xA;{&#xA;term: &#34;\&#34;(to) turn the tables\&#34;&#34;,&#xA;definition: &#34;\&#34;if you turn the tables, you reverse a situation to your advantage\&#34;&#34;,&#xA;stressed: &#34;\&#34;(to) t*urn the t*ables\&#34;&#34;,&#xA;id: &#34;\&#34;178e2b0f99d217dd424591195f2e456645e89ff3c571062b01666c6c4f06176d\&#34;&#34;&#xA;},&#xA;&#xA;&#xA;&#xA;{&#xA;term: &#34;\&#34;proper\&#34;&#34;,&#xA;definition: &#34;\&#34;the real or of good standards\&#34;&#34;,&#xA;stressed: &#34;\&#34;pr*oper\&#34;&#34;,&#xA;id: &#34;\&#34;8fba0154402a8d8a4d17973c13be405214fdd75e4c38a42aa55adf32e28ac4bf\&#34;&#34;&#xA;},&#xA;&#xA;&#xA;&#xA;{&#xA;term: &#34;\&#34;menial\&#34;&#34;,&#xA;definition: &#34;\&#34;menial work is boring, needs no skill, and is not important\&#34;&#34;,&#xA;stressed: &#34;\&#34;m*enial\&#34;&#34;,&#xA;id: &#34;\&#34;b3b44f74675ad739bc29a4b33d440b46960470d871cad80b14310896822d5542\&#34;&#34;&#xA;},&#xA;&#xA;&#xA;&#xA;{&#xA;term: &#34;\&#34;set\&#34;&#34;,&#xA;definition: &#34;\&#34;if a film or story is set in a particular place or period, the aciton is taking place there or then.\&#34;&#34;,&#xA;stressed: &#34;\&#34;set\&#34;&#34;,&#xA;id: &#34;\&#34;4cbd7d7f661c25fb2e1946d6e1b302368834f68123c9cec5e6c5b250be8326eb\&#34;&#34;&#xA;},&#xA;&#xA;&#xA;&#xA;{&#xA;term: &#34;\&#34;(to) shave\&#34;&#34;,&#xA;definition: &#34;\&#34;(to) cut off hair very close using a razor\&#34;&#34;,&#xA;stressed: &#34;\&#34;(to) shave\&#34;&#34;,&#xA;id: &#34;\&#34;b5cddb17e23c3983e3823cea63c0d8e95d34c6b0f542c364083e1fe505870c5a\&#34;&#34;&#xA;},&#xA;&#xA;&#xA;&#xA;{&#xA;term: &#34;\&#34;downsize\&#34;&#34;,&#xA;definition: &#34;\&#34;(to) make smaller\&#34;&#34;,&#xA;stressed: &#34;\&#34;d*o*wnsize\&#34;&#34;,&#xA;id: &#34;\&#34;a2525a669d2d1ca147a064eba1daa5281fe4cc6a27c293fa172d2b19dd2cc1b8\&#34;&#34;&#xA;},&#xA;&#xA;&#xA;].filter(card =&gt; card.term.trim() &amp;&amp; card.definition.trim());&#xA;&#xA;this.setId = &#34;/chapters/women_detectives/&#34;.replace(/\/+$/, &#39;&#39;).replace(/^\//, &#39;&#39;);&#xA;this.setTitle = &#34;Women Detectives&#34;;&#xA;this.cardData = {};&#xA;this.sessionStats = { reviewed: 0 }; &#xA;this.reviewedInSession = new Set();&#xA;this.currentIndex = 0;&#xA;this.isFlipped = false;&#xA;this.studyMode = &#39;term-to-definition&#39;;&#xA;this.viewMode = &#39;browse&#39;; &#xA;this.cardOrder = [...Array(this.flashcards.length).keys()];&#xA;&#xA;this.initDOM();&#xA;this.setupEventListeners();&#xA;&#xA;this.loadProgress().then(() =&gt; {&#xA;this.initializeSession();&#xA;this.updateDisplay();&#xA;});&#xA;}&#xA;&#xA;&#xA;&#xA;&#xA;processStressedText(text) {&#xA;    if (!text) return text;&#xA;    &#xA;    &#xA;    &#xA;    let processed = text.replace(/(\s?)\*([ayeiouwAEYIOUáéíóúÁÉÍÓÚ])/g, &#39;$1&lt;span class=&#34;stressed-vowel&#34;&gt;$2&lt;/span&gt;&#39;);&#xA;    &#xA;    return processed;&#xA;}&#xA;&#xA;&#xA;&#xA;&#xA;initDOM() {&#xA;this.elements = {&#xA;flashcard: document.getElementById(&#39;flashcard&#39;),&#xA;cardQuestion: document.getElementById(&#39;card-question&#39;),&#xA;cardQuestionBack: document.getElementById(&#39;card-question-back&#39;),&#xA;cardAnswer: document.getElementById(&#39;card-answer&#39;),&#xA;currentCard: document.getElementById(&#39;current-card&#39;),&#xA;totalCards: document.getElementById(&#39;total-cards&#39;),&#xA;prevBtn: document.getElementById(&#39;prev-btn&#39;),&#xA;nextBtn: document.getElementById(&#39;next-btn&#39;),&#xA;modeToggleBtn: document.getElementById(&#39;mode-toggle-btn&#39;),&#xA;earlyReviewBtn: document.getElementById(&#39;early-review-btn&#39;),&#xA;resetBtn: document.getElementById(&#39;reset-progress&#39;),&#xA;againBtn: document.getElementById(&#39;again-btn&#39;),&#xA;hardBtn: document.getElementById(&#39;hard-btn&#39;),&#xA;mediumBtn: document.getElementById(&#39;medium-btn&#39;),&#xA;easyBtn: document.getElementById(&#39;easy-btn&#39;),&#xA;reviewedCount: document.getElementById(&#39;reviewed-count&#39;),&#xA;againCount: document.getElementById(&#39;again-count&#39;),&#xA;hardCount: document.getElementById(&#39;hard-count&#39;),&#xA;mediumCount: document.getElementById(&#39;medium-count&#39;),&#xA;easyCount: document.getElementById(&#39;easy-count&#39;),&#xA;reviewCount: document.getElementById(&#39;review-count&#39;),&#xA;completionMessage: document.getElementById(&#39;completion-message&#39;),&#xA;completionText: document.getElementById(&#39;completion-text&#39;),&#xA;earlyReviewOption: document.getElementById(&#39;early-review-option&#39;),&#xA;modeRadios: document.querySelectorAll(&#39;input[name=&#34;study-mode&#34;]&#39;)&#xA;};&#xA;}&#xA;setupEventListeners() {&#xA;this.elements.flashcard.addEventListener(&#39;click&#39;, () =&gt; this.flipCard());&#xA;this.elements.prevBtn.addEventListener(&#39;click&#39;, () =&gt; this.prevCard());&#xA;this.elements.nextBtn.addEventListener(&#39;click&#39;, () =&gt; this.nextCard());&#xA;this.elements.modeToggleBtn.addEventListener(&#39;click&#39;, () =&gt; this.toggleViewMode());&#xA;this.elements.earlyReviewBtn.addEventListener(&#39;click&#39;, () =&gt; this.handleEarlyReview());&#xA;this.elements.resetBtn.addEventListener(&#39;click&#39;, () =&gt; this.resetProgress());&#xA;&#xA;this.elements.againBtn.addEventListener(&#39;click&#39;, () =&gt; this.markDifficulty(&#39;again&#39;));&#xA;this.elements.hardBtn.addEventListener(&#39;click&#39;, () =&gt; this.markDifficulty(&#39;hard&#39;));&#xA;this.elements.mediumBtn.addEventListener(&#39;click&#39;, () =&gt; this.markDifficulty(&#39;medium&#39;));&#xA;this.elements.easyBtn.addEventListener(&#39;click&#39;, () =&gt; this.markDifficulty(&#39;easy&#39;));&#xA;this.elements.modeRadios.forEach(radio =&gt; {&#xA;radio.addEventListener(&#39;change&#39;, (e) =&gt; this.changeStudyMode(e.target.value));&#xA;});&#xA;document.getElementById(&#39;close-completion&#39;).addEventListener(&#39;click&#39;, () =&gt; {&#xA;this.elements.completionMessage.style.display = &#39;none&#39;;&#xA;});&#xA;document.getElementById(&#39;early-review-option&#39;).addEventListener(&#39;click&#39;, () =&gt; {&#xA;this.elements.completionMessage.style.display = &#39;none&#39;;&#xA;this.startEarlyReview();&#xA;});&#xA;document.getElementById(&#39;browse-all-option&#39;).addEventListener(&#39;click&#39;, () =&gt; {&#xA;this.elements.completionMessage.style.display = &#39;none&#39;;&#xA;this.startBrowseMode();&#xA;});&#xA;}&#xA;&#xA;shuffleArray(array) {&#xA;const shuffled = [...array]; &#xA;for (let i = shuffled.length - 1; i &gt; 0; i--) {&#xA;const j = Math.floor(Math.random() * (i + 1));&#xA;[shuffled[i], shuffled[j]] = [shuffled[j], shuffled[i]];&#xA;}&#xA;return shuffled;&#xA;}&#xA;&#xA;getDueCards(includeEarly = false) {&#xA;const now = Date.now();&#xA;const allIndices = [...Array(this.flashcards.length).keys()];&#xA;if (includeEarly) {&#xA;const earlyThreshold = now + (24 * 60 * 60 * 1000);&#xA;return allIndices.filter(idx =&gt; {&#xA;const card = this.cardData[idx];&#xA;return !card || !card.nextReview || card.nextReview &lt;= earlyThreshold;&#xA;});&#xA;} else {&#xA;return allIndices.filter(idx =&gt; {&#xA;const card = this.cardData[idx];&#xA;return !card || !card.nextReview || card.nextReview &lt;= now;&#xA;});&#xA;}&#xA;}&#xA;&#xA;updateCardWithSM2(cardIndex, difficulty) {&#xA;if (!this.cardData[cardIndex]) {&#xA;this.cardData[cardIndex] = {&#xA;interval: 0,&#xA;easeFactor: 2.5,&#xA;reviewCount: 0,&#xA;lastReviewed: Date.now(),&#xA;nextReview: Date.now()&#xA;};&#xA;}&#xA;const card = this.cardData[cardIndex];&#xA;card.reviewCount++;&#xA;card.lastReviewed = Date.now();&#xA;card.lastDifficulty = difficulty; &#xA;let quality;&#xA;switch (difficulty) {&#xA;case &#39;again&#39;: quality = 0; break;&#xA;case &#39;hard&#39;: quality = 2; break;&#xA;case &#39;medium&#39;: quality = 3; break;&#xA;case &#39;easy&#39;: quality = 5; break;&#xA;default: quality = 3;&#xA;}&#xA;&#xA;if (quality &gt;= 3) {&#xA;if (card.reviewCount === 1) {&#xA;card.interval = quality === 5 ? 2 : 1; &#xA;} else if (card.reviewCount === 2) {&#xA;card.interval = 6;&#xA;} else {&#xA;card.interval = Math.round(card.interval * card.easeFactor);&#xA;}&#xA;} else {&#xA;card.interval = quality === 0 ? 0.007 : 1; &#xA;}&#xA;&#xA;if (quality === 0) {&#xA;card.easeFactor = Math.max(1.3, card.easeFactor - 0.2);&#xA;} else if (quality === 2) {&#xA;card.easeFactor = Math.max(1.3, card.easeFactor - 0.15);&#xA;} else if (quality === 3) {&#xA;card.easeFactor = Math.max(1.3, card.easeFactor - 0.02);&#xA;} else if (quality === 5) {&#xA;card.easeFactor = Math.min(2.6, card.easeFactor + 0.1);&#xA;}&#xA;card.nextReview = card.lastReviewed + (card.interval * 24 * 60 * 60 * 1000);&#xA;}&#xA;&#xA;async markDifficulty(level) {&#xA;if (!this.isFlipped) {&#xA;this.flipCard();&#xA;return;&#xA;}&#xA;if (this.viewMode !== &#39;study&#39;) {&#xA;return;&#xA;}&#xA;const cardIndex = this.cardOrder[this.currentIndex];&#xA;&#xA;if (!this.reviewedInSession.has(cardIndex)) {&#xA;this.sessionStats.reviewed++;&#xA;this.reviewedInSession.add(cardIndex);&#xA;}&#xA;&#xA;this.updateCardWithSM2(cardIndex, level);&#xA;&#xA;await this.saveProgress();&#xA;this.updateStatsDisplay();&#xA;&#xA;if (level === &#39;again&#39;) {&#xA;if (this.currentIndex &lt; this.cardOrder.length - 1) {&#xA;this.currentIndex++;&#xA;} else {&#xA;this.currentIndex = 0;&#xA;}&#xA;this.updateCard();&#xA;} else {&#xA;&#xA;this.cardOrder.splice(this.currentIndex, 1);&#xA;if (this.currentIndex &gt;= this.cardOrder.length &amp;&amp; this.cardOrder.length &gt; 0) {&#xA;this.currentIndex = this.cardOrder.length - 1;&#xA;}&#xA;if (this.cardOrder.length &gt; 0) {&#xA;this.updateCard();&#xA;} else {&#xA;this.saveProgress();&#xA;this.showCompletionMessage();&#xA;}&#xA;}&#xA;}&#xA;&#xA;startStudyMode() {&#xA;const dueCards = this.getDueCards();&#xA;if (dueCards.length &gt; 0) {&#xA;this.viewMode = &#39;study&#39;;&#xA;&#xA;this.cardOrder = this.shuffleArray(dueCards);&#xA;this.currentIndex = 0;&#xA;this.updateModeButton(&#39;📚 Studying&#39;, &#39;btn-primary&#39;);&#xA;this.updateCard();&#xA;} else {&#xA;this.checkForEarlyReview();&#xA;}&#xA;}&#xA;startEarlyReview() {&#xA;const allEarly = this.getDueCards(true);&#xA;const dueNow = this.getDueCards(false);&#xA;const earlyOnly = allEarly.filter(idx =&gt; !dueNow.includes(idx));&#xA;if (earlyOnly.length &gt; 0) {&#xA;this.viewMode = &#39;study&#39;;&#xA;&#xA;this.cardOrder = this.shuffleArray(earlyOnly);&#xA;this.currentIndex = 0;&#xA;this.updateModeButton(&#39;📚 Studying&#39;, &#39;btn-primary&#39;);&#xA;this.updateCard();&#xA;} else {&#xA;alert(&#34;No cards are available for early review right now.&#34;);&#xA;}&#xA;}&#xA;startBrowseMode() {&#xA;this.viewMode = &#39;browse&#39;;&#xA;&#xA;this.cardOrder = [...Array(this.flashcards.length).keys()];&#xA;this.currentIndex = 0;&#xA;this.updateModeButton(&#39;📖 Browsing&#39;, &#39;btn-secondary&#39;);&#xA;this.updateCard();&#xA;}&#xA;checkForEarlyReview() {&#xA;const allEarly = this.getDueCards(true);&#xA;const dueNow = this.getDueCards(false);&#xA;const earlyCount = allEarly.length - dueNow.length;&#xA;if (earlyCount &gt; 0) {&#xA;const message = `No cards are due right now, but you have ${earlyCount} card${earlyCount !== 1 ? &#39;s&#39; : &#39;&#39;} due within 24 hours.\n\nWould you like to review them early?`;&#xA;if (confirm(message)) {&#xA;this.startEarlyReview();&#xA;} else {&#xA;this.viewMode = &#39;browse&#39;;&#xA;this.startBrowseMode();&#xA;}&#xA;} else {&#xA;this.showCompletionMessage();&#xA;this.viewMode = &#39;browse&#39;;&#xA;}&#xA;}&#xA;&#xA;updateModeButton(text, className) {&#xA;this.elements.modeToggleBtn.textContent = text;&#xA;this.elements.modeToggleBtn.className = `btn ${className}`;&#xA;&#xA;const difficultyButtons = document.querySelector(&#39;.difficulty-buttons&#39;);&#xA;if (difficultyButtons) {&#xA;if (this.viewMode === &#39;study&#39;) {&#xA;difficultyButtons.style.display = &#39;flex&#39;;&#xA;} else {&#xA;difficultyButtons.style.display = &#39;none&#39;;&#xA;}&#xA;}&#xA;}&#xA;toggleViewMode() {&#xA;if (this.viewMode === &#39;browse&#39;) {&#xA;this.startStudyMode();&#xA;} else {&#xA;this.startBrowseMode();&#xA;}&#xA;&#xA;this.saveProgressSilent();&#xA;}&#xA;handleEarlyReview() {&#xA;const allEarly = this.getDueCards(true);&#xA;const dueNow = this.getDueCards(false);&#xA;const earlyCount = allEarly.length - dueNow.length;&#xA;if (earlyCount &gt; 0) {&#xA;this.startEarlyReview();&#xA;} else if (dueNow.length &gt; 0) {&#xA;alert(&#34;You have cards due for review! Use the Study button instead.&#34;);&#xA;} else {&#xA;alert(&#34;No cards are available for early review right now.&#34;);&#xA;}&#xA;}&#xA;&#xA;updateCard() {&#xA;if (this.flashcards.length === 0) {&#xA;this.elements.cardQuestion.innerHTML = &#34;No flashcards available&#34;;&#xA;this.elements.cardQuestionBack.innerHTML = &#34;No flashcards available&#34;;&#xA;this.elements.cardAnswer.innerHTML = &#34;Please add lexicon data to the front matter&#34;;&#xA;return;&#xA;}&#xA;if (this.currentIndex &lt; 0 || this.currentIndex &gt;= this.cardOrder.length) {&#xA;this.currentIndex = 0;&#xA;}&#xA;const cardIndex = this.cardOrder[this.currentIndex];&#xA;const card = this.flashcards[cardIndex];&#xA;if (!card) {&#xA;console.error(&#39;Invalid card at index:&#39;, cardIndex);&#xA;return;&#xA;}&#xA;let question, answer;&#xA;if (this.studyMode === &#39;term-to-definition&#39;) {&#xA;&#xA;question = card.stressed || card.term;&#xA;answer = card.definition;&#xA;} else {&#xA;question = card.definition;&#xA;&#xA;answer = card.stressed || card.term;&#xA;}&#xA;&#xA;this.elements.cardQuestion.innerHTML = this.processStressedText(question);&#xA;this.elements.cardQuestionBack.innerHTML = this.processStressedText(question);&#xA;this.elements.cardAnswer.innerHTML = this.processStressedText(answer);&#xA;this.elements.currentCard.textContent = this.currentIndex + 1;&#xA;this.elements.totalCards.textContent = this.cardOrder.length;&#xA;&#xA;this.elements.prevBtn.disabled = this.currentIndex === 0;&#xA;this.elements.nextBtn.disabled = this.currentIndex === this.cardOrder.length - 1;&#xA;&#xA;this.isFlipped = false;&#xA;this.elements.flashcard.classList.remove(&#39;flipped&#39;);&#xA;}&#xA;&#xA;updateStatsDisplay() {&#xA;const totalReviewed = Object.values(this.cardData).filter(card =&gt; card &amp;&amp; card.reviewCount &gt; 0).length;&#xA;const needsReview = this.getDueCards().length;&#xA;&#xA;const difficultyStats = { again: 0, hard: 0, medium: 0, easy: 0 };&#xA;for (let i = 0; i &lt; this.flashcards.length; i++) {&#xA;const card = this.cardData[i];&#xA;if (card &amp;&amp; card.lastDifficulty) {&#xA;difficultyStats[card.lastDifficulty]++;&#xA;}&#xA;}&#xA;this.elements.reviewedCount.textContent = totalReviewed;&#xA;this.elements.reviewCount.textContent = needsReview;&#xA;&#xA;if (this.elements.againCount) this.elements.againCount.textContent = difficultyStats.again;&#xA;if (this.elements.hardCount) this.elements.hardCount.textContent = difficultyStats.hard;&#xA;if (this.elements.mediumCount) this.elements.mediumCount.textContent = difficultyStats.medium;&#xA;this.elements.easyCount.textContent = difficultyStats.easy;&#xA;}&#xA;updateDisplay() {&#xA;this.updateCard();&#xA;this.updateStatsDisplay();&#xA;&#xA;const radio = document.querySelector(`input[value=&#34;${this.studyMode}&#34;]`);&#xA;if (radio) radio.checked = true;&#xA;&#xA;if (this.viewMode === &#39;study&#39;) {&#xA;this.updateModeButton(&#39;📚 Studying&#39;, &#39;btn-primary&#39;);&#xA;} else {&#xA;this.updateModeButton(&#39;📖 Browsing&#39;, &#39;btn-secondary&#39;);&#xA;}&#xA;}&#xA;&#xA;flipCard() {&#xA;this.isFlipped = !this.isFlipped;&#xA;this.elements.flashcard.classList.toggle(&#39;flipped&#39;);&#xA;}&#xA;nextCard() {&#xA;if (this.currentIndex &lt; this.cardOrder.length - 1) {&#xA;this.currentIndex++;&#xA;this.updateCard();&#xA;&#xA;if (this.viewMode === &#39;study&#39;) {&#xA;this.saveProgressSilent();&#xA;}&#xA;}&#xA;}&#xA;prevCard() {&#xA;if (this.currentIndex &gt; 0) {&#xA;this.currentIndex--;&#xA;this.updateCard();&#xA;&#xA;if (this.viewMode === &#39;study&#39;) {&#xA;this.saveProgressSilent();&#xA;}&#xA;}&#xA;}&#xA;changeStudyMode(mode) {&#xA;this.studyMode = mode;&#xA;this.updateCard();&#xA;&#xA;this.saveProgressSilent();&#xA;}&#xA;&#xA;showCompletionMessage() {&#xA;this.viewMode = &#39;browse&#39;;&#xA;this.updateModeButton(&#39;📖 Browsing&#39;, &#39;btn-secondary&#39;);&#xA;const nextReview = this.getNextReviewTime();&#xA;const allEarly = this.getDueCards(true);&#xA;const dueNow = this.getDueCards(false);&#xA;const earlyCards = allEarly.length - dueNow.length;&#xA;let message = &#34;You&#39;ve reviewed all due cards!&#34;;&#xA;if (nextReview) {&#xA;const timeUntil = nextReview - Date.now();&#xA;const hoursUntil = Math.ceil(timeUntil / (1000 * 60 * 60));&#xA;const daysUntil = Math.ceil(timeUntil / (1000 * 60 * 60 * 24));&#xA;if (hoursUntil &lt; 24) {&#xA;message += ` Next cards will be ready in about ${hoursUntil} hour${hoursUntil !== 1 ? &#39;s&#39; : &#39;&#39;}.`;&#xA;} else {&#xA;message += ` Next cards will be ready in about ${daysUntil} day${daysUntil !== 1 ? &#39;s&#39; : &#39;&#39;}.`;&#xA;}&#xA;}&#xA;this.elements.completionText.textContent = message;&#xA;if (earlyCards &gt; 0) {&#xA;this.elements.earlyReviewOption.style.display = &#39;inline-block&#39;;&#xA;this.elements.earlyReviewOption.textContent = `⏰ Review ${earlyCards} Early Card${earlyCards !== 1 ? &#39;s&#39; : &#39;&#39;}`;&#xA;} else {&#xA;this.elements.earlyReviewOption.style.display = &#39;none&#39;;&#xA;}&#xA;this.elements.completionMessage.style.display = &#39;flex&#39;;&#xA;this.saveProgressSilent();&#xA;}&#xA;getNextReviewTime() {&#xA;const now = Date.now();&#xA;let earliest = null;&#xA;for (let i = 0; i &lt; this.flashcards.length; i++) {&#xA;const card = this.cardData[i];&#xA;if (card &amp;&amp; card.nextReview &amp;&amp; card.nextReview &gt; now) {&#xA;if (!earliest || card.nextReview &lt; earliest) {&#xA;earliest = card.nextReview;&#xA;}&#xA;}&#xA;}&#xA;return earliest;&#xA;}&#xA;&#xA;resetProgress() {&#xA;this.cardData = {};&#xA;this.sessionStats = { reviewed: 0 };&#xA;this.reviewedInSession = new Set();&#xA;this.viewMode = &#39;browse&#39;;&#xA;this.cardOrder = [...Array(this.flashcards.length).keys()];&#xA;this.currentIndex = 0;&#xA;this.updateDisplay();&#xA;this.saveProgressSilent();&#xA;}&#xA;&#xA;initializeSession() {&#xA;if (this.viewMode === &#39;study&#39;) {&#xA;const dueCards = this.getDueCards();&#xA;if (dueCards.length &gt; 0) {&#xA;&#xA;this.cardOrder = this.shuffleArray(dueCards);&#xA;this.currentIndex = 0;&#xA;this.updateModeButton(&#39;📚 Studying&#39;, &#39;btn-primary&#39;);&#xA;} else {&#xA;this.viewMode = &#39;browse&#39;;&#xA;this.cardOrder = [...Array(this.flashcards.length).keys()];&#xA;this.currentIndex = Math.min(this.currentIndex, this.cardOrder.length - 1);&#xA;this.updateModeButton(&#39;📖 Browsing&#39;, &#39;btn-secondary&#39;);&#xA;}&#xA;} else {&#xA;&#xA;this.cardOrder = [...Array(this.flashcards.length).keys()];&#xA;this.currentIndex = Math.min(this.currentIndex, this.cardOrder.length - 1);&#xA;this.updateModeButton(&#39;📖 Browsing&#39;, &#39;btn-secondary&#39;);&#xA;}&#xA;}&#xA;&#xA;async saveProgress() {&#xA;this.saveToLocalStorage();&#xA;try {&#xA;const { data: { session }, error } = await supabaseClient.auth.getSession();&#xA;if (error || !session?.user?.id) {&#xA;return;&#xA;}&#xA;const progressData = {&#xA;user_id: session.user.id,&#xA;set_id: this.setId,&#xA;set_title: this.setTitle,&#xA;card_data: {&#xA;cardOrder: this.cardOrder,&#xA;currentIndex: this.currentIndex,&#xA;studyMode: this.studyMode,&#xA;viewMode: this.viewMode,&#xA;cardData: this.cardData&#xA;},&#xA;stats: this.sessionStats,&#xA;updated_at: new Date().toISOString()&#xA;};&#xA;const { error: saveError } = await supabaseClient&#xA;.from(&#39;flashcard_progress&#39;)&#xA;.upsert(progressData, { onConflict: &#39;user_id,set_id&#39; });&#xA;if (saveError) {&#xA;console.error(&#39;Supabase save error:&#39;, saveError);&#xA;}&#xA;} catch (e) {&#xA;console.error(&#39;Error saving progress:&#39;, e);&#xA;}&#xA;}&#xA;&#xA;async saveProgressSilent() {&#xA;this.saveToLocalStorage();&#xA;try {&#xA;const { data: { session }, error } = await supabaseClient.auth.getSession();&#xA;if (error || !session?.user?.id) {&#xA;return;&#xA;}&#xA;const progressData = {&#xA;user_id: session.user.id,&#xA;set_id: this.setId,&#xA;set_title: this.setTitle,&#xA;card_data: {&#xA;cardOrder: this.cardOrder,&#xA;currentIndex: this.currentIndex,&#xA;studyMode: this.studyMode,&#xA;viewMode: this.viewMode,&#xA;cardData: this.cardData&#xA;},&#xA;stats: this.sessionStats,&#xA;updated_at: new Date().toISOString()&#xA;};&#xA;await supabaseClient&#xA;.from(&#39;flashcard_progress&#39;)&#xA;.upsert(progressData, { onConflict: &#39;user_id,set_id&#39; });&#xA;} catch (e) {&#xA;console.error(&#39;Error saving progress silently:&#39;, e);&#xA;}&#xA;}&#xA;async loadProgress() {&#xA;&#xA;this.cardData = {};&#xA;this.sessionStats = { reviewed: 0 };&#xA;this.reviewedInSession = new Set();&#xA;try {&#xA;const { data: { session }, error } = await supabaseClient.auth.getSession();&#xA;if (error || !session?.user?.id) {&#xA;this.loadFromLocalStorage();&#xA;return;&#xA;}&#xA;const { data, error: dbError } = await supabaseClient&#xA;.from(&#39;flashcard_progress&#39;)&#xA;.select(&#39;*&#39;)&#xA;.eq(&#39;user_id&#39;, session.user.id)&#xA;.eq(&#39;set_id&#39;, this.setId)&#xA;.single();&#xA;if (dbError &amp;&amp; dbError.code !== &#39;PGRST116&#39;) {&#xA;console.error(&#39;Database error:&#39;, dbError);&#xA;this.loadFromLocalStorage();&#xA;return;&#xA;}&#xA;if (data) {&#xA;this.loadFromData(data);&#xA;&#xA;await this.migrateLocalStorageIfNewer(data.updated_at);&#xA;} else {&#xA;this.loadFromLocalStorage();&#xA;if (session?.user) {&#xA;await this.saveProgressSilent();&#xA;}&#xA;}&#xA;} catch (e) {&#xA;console.error(&#39;Error loading progress:&#39;, e);&#xA;this.loadFromLocalStorage();&#xA;}&#xA;}&#xA;&#xA;loadFromData(data) {&#xA;if (data.card_data) {&#xA;this.cardOrder = this.validateArray(data.card_data.cardOrder, this.flashcards.length) ||&#xA;[...Array(this.flashcards.length).keys()];&#xA;this.cardData = this.validateCardData(data.card_data.cardData) || {};&#xA;this.currentIndex = Math.max(0, Math.min(data.card_data.currentIndex || 0, this.cardOrder.length - 1));&#xA;this.studyMode = [&#39;term-to-definition&#39;, &#39;definition-to-term&#39;].includes(data.card_data.studyMode) ?&#xA;data.card_data.studyMode : &#39;term-to-definition&#39;;&#xA;this.viewMode = [&#39;browse&#39;, &#39;study&#39;].includes(data.card_data.viewMode) ?&#xA;data.card_data.viewMode : &#39;browse&#39;;&#xA;}&#xA;if (data.stats &amp;&amp; typeof data.stats === &#39;object&#39;) {&#xA;this.sessionStats = {&#xA;reviewed: data.stats.reviewed || 0&#xA;};&#xA;}&#xA;}&#xA;loadFromLocalStorage() {&#xA;const storageKey = `flashcards_${this.setId}`;&#xA;const saved = localStorage.getItem(storageKey);&#xA;if (saved) {&#xA;try {&#xA;const data = JSON.parse(saved);&#xA;this.loadFromData({&#xA;card_data: {&#xA;cardOrder: data.cardOrder,&#xA;cardData: data.cardData,&#xA;currentIndex: data.currentIndex,&#xA;studyMode: data.studyMode,&#xA;viewMode: data.viewMode&#xA;},&#xA;stats: data.sessionStats&#xA;});&#xA;} catch (e) {&#xA;console.error(&#39;Error parsing localStorage:&#39;, e);&#xA;}&#xA;}&#xA;}&#xA;async migrateLocalStorageIfNewer(dbUpdatedAt) {&#xA;const storageKey = `flashcards_${this.setId}`;&#xA;const saved = localStorage.getItem(storageKey);&#xA;if (!saved) return;&#xA;try {&#xA;const localData = JSON.parse(saved);&#xA;const localUpdated = new Date(localData.lastUpdated || 0);&#xA;const dbUpdated = new Date(dbUpdatedAt);&#xA;if (localUpdated &gt; dbUpdated) {&#xA;this.loadFromData({&#xA;card_data: {&#xA;cardOrder: localData.cardOrder,&#xA;cardData: localData.cardData,&#xA;currentIndex: localData.currentIndex,&#xA;studyMode: localData.studyMode,&#xA;viewMode: localData.viewMode&#xA;},&#xA;stats: localData.sessionStats&#xA;});&#xA;await this.saveProgressSilent();&#xA;}&#xA;} catch (e) {&#xA;console.error(&#39;Error during migration:&#39;, e);&#xA;}&#xA;}&#xA;saveToLocalStorage() {&#xA;const storageKey = `flashcards_${this.setId}`;&#xA;const data = {&#xA;cardOrder: this.cardOrder,&#xA;currentIndex: this.currentIndex,&#xA;studyMode: this.studyMode,&#xA;viewMode: this.viewMode,&#xA;cardData: this.cardData,&#xA;sessionStats: this.sessionStats,&#xA;lastUpdated: new Date().toISOString(),&#xA;setTitle: this.setTitle&#xA;};&#xA;try {&#xA;localStorage.setItem(storageKey, JSON.stringify(data));&#xA;} catch (e) {&#xA;console.error(&#39;Error saving to localStorage:&#39;, e);&#xA;}&#xA;}&#xA;&#xA;validateArray(arr, expectedLength) {&#xA;if (!Array.isArray(arr) || arr.length !== expectedLength) return null;&#xA;return arr.every(idx =&gt; Number.isInteger(idx) &amp;&amp; idx &gt;= 0 &amp;&amp; idx &lt; expectedLength) ? arr : null;&#xA;}&#xA;validateCardData(data) {&#xA;if (!data || typeof data !== &#39;object&#39;) return null;&#xA;const validated = {};&#xA;for (const [key, value] of Object.entries(data)) {&#xA;if (value &amp;&amp; typeof value === &#39;object&#39; &amp;&amp;&#xA;typeof value.interval === &#39;number&#39; &amp;&amp;&#xA;typeof value.easeFactor === &#39;number&#39;) {&#xA;validated[key] = value;&#xA;}&#xA;}&#xA;return validated;&#xA;}&#xA;}&#xA;&#xA;document.addEventListener(&#39;DOMContentLoaded&#39;, () =&gt; {&#xA;updateAuthLink();&#xA;window.flashcardSystem = new FlashcardSystem();&#xA;});&#xA;&#xA;supabaseClient.auth.onAuthStateChange(async (event, session) =&gt; {&#xA;console.log(&#39;Auth state changed:&#39;, event);&#xA;updateAuthLink();&#xA;&#xA;});&#xA;&#xA;window.addEventListener(&#39;focus&#39;, () =&gt; {&#xA;setTimeout(updateAuthLink, 1000); &#xA;});&#xA;&lt;/script&gt;</description>
      
    </item>
    
  </channel>
</rss>
