PageSourceSearch

https://feminine-rising.netlify.app/library

html feminine-rising.netlify.app collected 2026-10-03 10:43:45 UTC 37,946 bytes, 1,241 lines download raw bytes

1<!DOCTYPE html>
2<html lang="en">
3<head>
4<meta charset="UTF-8">
5<meta name="viewport" content="width=device-width, initial-scale=1.0">
6<title>The Golden Path Library</title>
7<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32.png">
8<link rel="icon" type="image/png" sizes="192x192" href="/favicon-192.png">
9<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png">
10<link rel="preconnect" href="https://fonts.googleapis.com">
11<link href="https://fonts.googleapis.com/css2?family=Cormorant+Garamond:ital,wght@0,400;0,600;1,400&family=Lora:ital,wght@0,400;0,600;1,400&family=Marcellus&family=Great+Vibes&display=swap" rel="stylesheet">
12<script src="https://cdn.jsdelivr.net/npm/@supabase/supabase-js@2"></script>
12
13<style>
14:root {
15  --gold: #C5A55A;
16  --gold-light: #D4BA7A;
17  --gold-pale: #F0E6CC;
18  --plum: #8B2252;
19  --plum-deep: #6B1A42;
20  --berry: #940E4B;
21  --cream: #FBF8F3;
22  --cream-warm: #F7F0E5;
23  --charcoal: #2E2E2E;
24}
25
26* { margin: 0; padding: 0; box-sizing: border-box; }
27
28body {
29  font-family: 'Lora', serif;
30  background: var(--cream);
31  color: var(--charcoal);
32  min-height: 100vh;
33}
34
35/* ============================================
36   PASSWORD SCREEN
37   ============================================ */
38#password-screen {
39  min-height: 100vh;
40  display: flex;
41  flex-direction: column;
42  align-items: center;
43  justify-content: center;
44  background: var(--cream);
45  position: relative;
46}
47
48#password-screen::before {
49  content: '';
50  position: absolute;
51  top: 0;
52  left: 0;
53  right: 0;
54  height: 200px;
55  background: var(--plum);
56}
57
58.password-card {
59  position: relative;
60  background: var(--cream);
61  border: 1px solid var(--gold-light);
62  border-radius: 12px;
63  padding: 60px 50px 50px;
64  max-width: 460px;
65  width: 90%;
66  text-align: center;
67  box-shadow: 0 8px 40px rgba(139, 34, 82, 0.08);
68  margin-top: -40px;
69}
70
71.password-logo {
72  width: 60px;
73  height: 60px;
74  margin-bottom: 20px;
75}
76
77.password-title {
78  font-family: 'Marcellus', serif;
79  font-size: 13px;
80  letter-spacing: 4px;
81  color: var(--gold);
82  text-transform: uppercase;
83  margin-bottom: 8px;
84}
85
86.password-heading {
87  font-family: 'Cormorant Garamond', serif;
88  font-size: 32px;
89  color: var(--plum-deep);
90  margin-bottom: 6px;
91  font-weight: 400;
92}
93
94.password-subtitle {
95  font-family: 'Cormorant Garamond', serif;
96  font-style: italic;
97  font-size: 16px;
98  color: var(--berry);
99  margin-bottom: 30px;
100}
101
102.password-divider {
103  display: flex;
104  align-items: center;
105  gap: 12px;
106  margin-bottom: 30px;
107}
108
109.password-divider::before,
110.password-divider::after {
111  content: '';
112  flex: 1;
113  height: 1px;
114  background: var(--gold-light);
115}
116
117.password-divider span {
118  color: var(--gold);
119  font-size: 14px;
120}
121
122.password-prompt {
123  font-family: 'Cormorant Garamond', serif;
124  font-style: italic;
125  font-size: 15px;
126  color: var(--plum);
127  margin-bottom: 20px;
128}
129
130.password-input {
131  width: 100%;
132  padding: 14px 20px;
133  border: 1px solid var(--gold-light);
134  border-radius: 8px;
135  background: white;
136  font-family: 'Lora', serif;
137  font-size: 14px;
138  color: var(--charcoal);
139  text-align: center;
140  letter-spacing: 2px;
141  outline: none;
142  transition: border-color 0.3s;
143  margin-bottom: 16px;
144}
145
146.password-input:focus {
147  border-color: var(--gold);
148  box-shadow: 0 0 0 3px rgba(197, 165, 90, 0.15);
149}
150
151.password-input::placeholder {
152  color: #bbb;
153  letter-spacing: 1px;
154}
155
156.password-btn {
157  width: 100%;
158  padding: 14px;
159  background: var(--plum);
160  color: var(--gold);
161  border: none;
162  border-radius: 8px;
163  font-family: 'Marcellus', serif;
164  font-size: 13px;
165  letter-spacing: 3px;
166  text-transform: uppercase;
167  cursor: pointer;
168  transition: all 0.3s;
169}
170
171.password-btn:hover {
172  background: var(--plum-deep);
173  box-shadow: 0 4px 16px rgba(107, 26, 66, 0.3);
174}
175
176.password-error {
177  color: var(--berry);
178  font-size: 13px;
179  font-style: italic;
180  margin-top: 12px;
181  opacity: 0;
182  transition: opacity 0.3s;
183}
184
185.password-error.show { opacity: 1; }
186
187/* ============================================
188   LIBRARY (hidden until authenticated)
189   ============================================ */
190#library {
191  display: none;
192  min-height: 100vh;
193}
194
195/* Top banner */
196.back-to-hub {
197  position: absolute;
198  top: 16px;
199  left: 20px;
200  display: inline-flex;
201  align-items: center;
202  gap: 6px;
203  padding: 8px 18px;
204  background: rgba(107, 26, 66, 0.7);
205  border: 1px solid rgba(197, 165, 90, 0.4);
206  border-radius: 6px;
207  color: var(--gold-light);
208  font-family: 'Marcellus', serif;
209  font-size: 10px;
210  letter-spacing: 2px;
211  text-transform: uppercase;
212  text-decoration: none;
213  transition: all 0.3s;
214  z-index: 10;
215}
216
217.back-to-hub:hover {
218  background: rgba(107, 26, 66, 0.95);
219  border-color: var(--gold);
220  color: var(--gold);
221}
222
223.library-banner {
224  background: var(--plum);
225  padding: 40px 20px 36px;
226  text-align: center;
227  position: relative;
228}
229
230.library-banner::after {
231  content: '';
232  position: absolute;
233  bottom: -3px;
234  left: 10%;
235  right: 10%;
236  height: 3px;
237  background: var(--gold);
238}
239
240.banner-eyebrow {
241  font-family: 'Marcellus', serif;
242  font-size: 12px;
243  letter-spacing: 5px;
244  color: var(--gold);
245  text-transform: uppercase;
246  margin-bottom: 10px;
247}
248
249.banner-title {
250  font-family: 'Cormorant Garamond', serif;
251  font-size: 38px;
252  color: white;
253  font-weight: 400;
254  margin-bottom: 4px;
255}
256
257.banner-subtitle {
258  font-family: 'Cormorant Garamond', serif;
259  font-style: italic;
260  font-size: 16px;
261  color: var(--gold-light);
262}
263
264/* Welcome section */
265.welcome-section {
266  max-width: 720px;
267  margin: 0 auto;
268  padding: 50px 30px 30px;
269  text-align: center;
270}
271
272.welcome-text {
273  font-family: 'Cormorant Garamond', serif;
274  font-style: italic;
275  font-size: 18px;
276  line-height: 1.7;
277  color: var(--plum);
278  margin-bottom: 8px;
279}
280
281.welcome-signature {
282  font-family: 'Great Vibes', cursive;
283  font-size: 28px;
284  color: var(--gold);
285}
286
287/* Diamond divider */
288.diamond-divider {
289  display: flex;
290  align-items: center;
291  justify-content: center;
292  gap: 14px;
293  padding: 10px 0 30px;
294  max-width: 500px;
295  margin: 0 auto;
296}
297
298.diamond-divider::before,
299.diamond-divider::after {
300  content: '';
301  flex: 1;
302  height: 1px;
303  background: var(--gold-light);
304}
305
306.diamond-divider span {
307  color: var(--gold);
308  font-size: 10px;
309}
310
311/* Teachings grid */
312.teachings-container {
313  max-width: 800px;
314  margin: 0 auto;
315  padding: 0 30px 60px;
316}
317
318.teaching-card {
319  display: flex;
320  align-items: flex-start;
321  gap: 16px;
322  padding: 22px 24px;
323  margin-bottom: 12px;
324  background: white;
325  border-radius: 10px;
326  border: 1px solid rgba(197, 165, 90, 0.2);
327  transition: all 0.3s;
328  text-decoration: none;
329  color: inherit;
330  cursor: pointer;
331}
332
333.teaching-card:hover {
334  border-color: var(--gold);
335  box-shadow: 0 4px 20px rgba(197, 165, 90, 0.15);
336  transform: translateY(-1px);
337}
338
339.teaching-number {
340  font-family: 'Marcellus', serif;
341  font-size: 12px;
342  color: var(--gold);
343  background: var(--cream-warm);
344  width: 32px;
345  height: 32px;
346  border-radius: 50%;
347  display: flex;
348  align-items: center;
349  justify-content: center;
350  flex-shrink: 0;
351  margin-top: 2px;
352}
353
354.teaching-info { flex: 1; }
355
356.teaching-title {
357  font-family: 'Cormorant Garamond', serif;
358  font-size: 19px;
359  color: var(--plum-deep);
360  margin-bottom: 3px;
361  font-weight: 600;
362}
363
364.teaching-subtitle {
365  font-family: 'Lora', serif;
366  font-size: 13.5px;
367  color: var(--berry);
368  font-style: italic;
369  opacity: 0.95;
370}
371
372.teaching-download {
373  font-family: 'Marcellus', serif;
374  font-size: 11px;
375  letter-spacing: 1.5px;
376  color: var(--berry);
377  text-transform: uppercase;
378  align-self: center;
379  flex-shrink: 0;
380  opacity: 0.85;
381  transition: opacity 0.3s;
382  font-weight: 600;
383}
384
385.teaching-card:hover .teaching-download {
386  opacity: 1;
387}
388
389/* Bookmark button — berry outline for legibility on cream */
390.bookmark-btn {
391  background: none;
392  border: none;
393  cursor: pointer;
394  font-size: 24px;
395  color: var(--berry);
396  opacity: 0.55;
397  padding: 4px 8px;
398  align-self: center;
399  flex-shrink: 0;
400  transition: all 0.2s;
401  line-height: 1;
402}
403.bookmark-btn:hover {
404  color: var(--berry);
405  opacity: 1;
406  transform: scale(1.15);
407}
408.bookmark-btn.bookmarked {
409  color: var(--berry);
410  opacity: 1;
411}
412
413/* Favorites filter row */
414.library-toolbar {
415  max-width: 760px;
416  margin: 0 auto 18px;
417  padding: 0 24px;
418  display: flex;
419  align-items: center;
420  justify-content: flex-end;
421  gap: 10px;
422  flex-wrap: wrap;
423}
424.fav-filter-btn {
425  display: inline-flex;
426  align-items: center;
427  gap: 6px;
428  padding: 9px 18px;
429  background: white;
430  border: 1px solid var(--gold);
431  border-radius: 18px;
432  font-family: 'Marcellus', serif;
433  font-size: 11px;
434  letter-spacing: 1.5px;
435  text-transform: uppercase;
436  color: var(--berry);
437  font-weight: 600;
438  cursor: pointer;
439  transition: all 0.3s;
440}
441.fav-filter-btn:hover {
442  border-color: var(--berry);
443  color: var(--berry);
444}
445.fav-filter-btn.active {
446  background: var(--berry);
447  color: white;
448  border-color: var(--berry);
449}
450.teaching-card.hidden-by-filter { display: none !important; }
451
452/* Start Here card */
453.start-here-card {
454  background: var(--cream-warm);
455  border: 2px solid var(--gold);
456  box-shadow: 0 4px 20px rgba(197, 165, 90, 0.15);
457}
458
459.start-here-card:hover {
460  box-shadow: 0 6px 28px rgba(197, 165, 90, 0.25);
461}
462
463.start-here-icon {
464  color: var(--gold);
465  font-size: 24px;
466  flex-shrink: 0;
467  width: 32px;
468  text-align: center;
469  margin-top: 2px;
470}
471
472/* Bonus section */
473.bonus-section {
474  max-width: 800px;
475  margin: 0 auto;
476  padding: 0 30px 50px;
477}
478
479.bonus-heading {
480  font-family: 'Marcellus', serif;
481  font-size: 12px;
482  letter-spacing: 4px;
483  color: var(--gold);
484  text-transform: uppercase;
485  text-align: center;
486  margin-bottom: 20px;
487}
488
489.bonus-card {
490  display: flex;
491  align-items: center;
492  gap: 16px;
493  padding: 18px 24px;
494  margin-bottom: 10px;
495  background: var(--cream-warm);
496  border-radius: 10px;
497  border: 1px solid rgba(197, 165, 90, 0.15);
498  transition: all 0.3s;
499  text-decoration: none;
500  color: inherit;
501  cursor: pointer;
502}
503
504.bonus-card:hover {
505  border-color: var(--gold);
506  box-shadow: 0 4px 16px rgba(197, 165, 90, 0.12);
507}
508
509.bonus-icon {
510  color: var(--gold);
511  font-size: 18px;
512  flex-shrink: 0;
513}
514
515.bonus-title {
516  font-family: 'Cormorant Garamond', serif;
517  font-size: 17px;
518  color: var(--plum-deep);
519  font-weight: 600;
520}
521
522.bonus-subtitle {
523  font-size: 12px;
524  color: var(--charcoal);
525  opacity: 0.7;
526}
527
528/* Footer */
529.library-footer {
530  text-align: center;
531  padding: 30px 20px 40px;
532  border-top: 1px solid var(--gold-light);
533  position: relative;
534}
535
536.library-footer::before {
537  content: '\2666\FE0E';
538  position: absolute;
539  top: -8px;
540  left: 50%;
541  transform: translateX(-50%);
542  background: var(--cream);
543  padding: 0 12px;
544  color: var(--gold);
545  font-size: 10px;
546}
547
548.footer-logo {
549  width: 36px;
550  height: 36px;
551  margin-bottom: 8px;
552}
553
554.footer-brand {
555  font-family: 'Marcellus', serif;
556  font-size: 9px;
557  letter-spacing: 4px;
558  color: var(--gold);
559  text-transform: uppercase;
560  margin-bottom: 6px;
561}
562
563.footer-copy {
564  font-size: 9px;
565  color: var(--gold);
566  opacity: 0.7;
567  max-width: 500px;
568  margin: 0 auto;
569  line-height: 1.5;
570}
571
572/* Responsive */
573@media (max-width: 600px) {
574  .password-card { padding: 40px 30px 36px; }
575  .banner-title { font-size: 28px; }
576  .teaching-card { padding: 16px; }
577  .teaching-title { font-size: 17px; }
578  .teaching-download { display: none; }
579}
580
581
582/* iOS Safari auto-zoom fix: inputs must be at least 16px to prevent zoom-on-focus */
583@media (max-width: 768px) {
584  input[type="text"],
585  input[type="email"],
586  input[type="password"],
587  input[type="search"],
588  input[type="number"],
589  input[type="tel"],
590  input[type="url"],
591  textarea,
592  select {
593    font-size: 16px !important;
594  }
595}
596</style>
597</head>
598<body>
599
600<!-- ============================================
601     PASSWORD SCREEN
602     ============================================ -->
603<div id="password-screen">
604  <a class='back-to-hub' href='/' style='position:fixed;top:16px;left:20px;'>&larr; Return to Main Page</a>
605  <div class="password-card">
606    <img src="feminine-rising-logo.png" alt="Feminine Rising" class="password-logo">
607    <div class="password-title">The Golden Path</div>
608    <h1 class="password-heading">Library</h1>
609    <div class="password-subtitle">Your Sacred Resource Collection</div>
610
611    <div class="password-divider"><span>&#9830;&#xFE0E;</span></div>
612
613    <p class="password-prompt">Please enter your access code to continue</p>
614    <input type="text" id="password-input" class="password-input" placeholder="Access Code" autofocus>
615    <button onclick="checkPassword()" class="password-btn">Continue</button>
616    <p id="password-error" class="password-error">The access code you entered is not recognized. Please try again or contact [email protected] if you have questions.</p>
617  </div>
618</div>
619
620<!-- ============================================
621     AUTH SCREEN (Email + Password) — appears AFTER access code
622     ============================================ -->
623<div id="auth-screen" style="display:none;min-height:100vh;align-items:center;justify-content:center;background:var(--cream);position:relative;flex-direction:column;">
624  <a class='back-to-hub' href='/' style='position:fixed;top:16px;left:20px;'>&larr; Return to Main Page</a>
625  <div class="password-card" style="max-width:460px;">
626    <img src="feminine-rising-logo.png" alt="Feminine Rising" class="password-logo">
627    <div class="password-title">The Golden Path</div>
628    <h1 class="password-heading" id="auth-heading">Welcome, Sister</h1>
629    <p class="password-subtitle" id="auth-subtitle">Create your account to enter the library.</p>
630
631    <div class="password-divider"><span>&#9830;&#xFE0E;</span></div>
632
633    <p style="font-family:'Cormorant Garamond',serif;font-style:italic;font-size:14px;color:var(--plum);margin-bottom:18px;line-height:1.5;">
634      If you're already in the Private Mentorship hub, use the same email & password you use there.
635    </p>
636
637    <input type="email" id="auth-email" class="password-input" placeholder="[email protected]" autocomplete="email" autocapitalize="none" autocorrect="off" spellcheck="false" style="text-align:left;letter-spacing:0;">
638    <div style="position:relative;">
639      <input type="password" id="auth-password" class="password-input" placeholder="Create a password" autocomplete="current-password" autocapitalize="none" autocorrect="off" spellcheck="false" style="text-align:left;letter-spacing:0;padding-right:48px;">
640      <button type="button" onclick="toggleAuthPasswordVisibility()" aria-label="Show or hide password" style="position:absolute;right:12px;top:50%;transform:translateY(-65%);background:none;border:none;cursor:pointer;font-size:18px;color:var(--gold);padding:4px 8px;line-height:1;">
641        <span id="auth-eye-icon">&#128065;</span>
642      </button>
643    </div>
644    <button id="auth-send-btn" onclick="authSubmit()" class="password-btn">Create My Account</button>
645    <p id="auth-message" class="password-error" style="opacity:0;transition:opacity 0.3s;"></p>
646    <div style="margin-top:18px;">
647      <button id="auth-toggle" onclick="toggleAuthMode()" style="background:none;border:none;color:var(--plum);font-family:'Cormorant Garamond',serif;font-size:14px;font-style:italic;cursor:pointer;letter-spacing:0.3px;opacity:0.85;transition:opacity 0.2s;" onmouseover="this.style.opacity='1'" onmouseout="this.style.opacity='0.85'">Already have an account? Sign in</button>
648    </div>
649    <div id="forgot-row" style="margin-top:10px;display:none;">
650      <button onclick="sendPasswordReset()" style="background:none;border:none;color:var(--gold);font-family:'Marcellus',serif;font-size:10px;letter-spacing:2px;cursor:pointer;text-transform:uppercase;opacity:0.8;transition:opacity 0.2s;" onmouseover="this.style.opacity='1'" onmouseout="this.style.opacity='0.8'">Forgot password?</button>
651    </div>
652  </div>
653</div>
654
655<!-- ============================================
656     RESET PASSWORD SCREEN (after clicking email link)
657     ============================================ -->
658<div id="reset-screen" style="display:none;min-height:100vh;align-items:center;justify-content:center;background:var(--cream);position:relative;flex-direction:column;">
659  <div class="password-card" style="max-width:460px;">
660    <img src="feminine-rising-logo.png" alt="Feminine Rising" class="password-logo">
661    <h1 class="password-heading">Set a New Password</h1>
662    <p class="password-subtitle">Choose a new password for your account.</p>
663    <div class="password-divider"><span>&#9830;&#xFE0E;</span></div>
664    <input type="password" id="reset-password" class="password-input" placeholder="New password (8+ characters)" autocomplete="new-password" autocapitalize="none" autocorrect="off" spellcheck="false" style="text-align:left;letter-spacing:0;">
665    <input type="password" id="reset-password-confirm" class="password-input" placeholder="Confirm new password" autocomplete="new-password" autocapitalize="none" autocorrect="off" spellcheck="false" style="text-align:left;letter-spacing:0;">
666    <button id="reset-submit-btn" onclick="updatePasswordSubmit()" class="password-btn">Update Password</button>
667    <p id="reset-message" class="password-error" style="opacity:0;transition:opacity 0.3s;"></p>
668  </div>
669</div>
670
671<!-- ============================================
672     LIBRARY
673     ============================================ -->
674<div id="library">
675
676  <!-- Banner -->
677  <header class="library-banner">
678    <a class='back-to-hub' href='/'>&larr; Return to Main Page</a>
679    <div class="banner-eyebrow">The Golden Path</div>
680    <h1 class="banner-title">Library</h1>
681    <p class="banner-subtitle">Your Sacred Resource Collection ~ 2026</p>
682  </header>
683
684  <!-- Welcome -->
685  <section class="welcome-section">
686    <p class="welcome-text">
687      Welcome to your Golden Path Library. These teachings are yours to return to,
688      revisit, and carry forward as living resources on your journey.
689    </p>
690  </section>
691
692  <div class="diamond-divider"><span>&#9830;&#xFE0E;</span></div>
693
694  <!-- Library Toolbar -->
695  <div class="library-toolbar">
696    <button class="fav-filter-btn" id="fav-filter-btn" onclick="toggleFavoritesFilter()">
697      <span id="fav-filter-icon">&#9825;</span> <span id="fav-filter-label">Show Favorites</span>
698    </button>
699  </div>
700
701  <!-- Teachings -->
702  <section class="teachings-container">
703
704    <!-- Start Here -->
705    <a class='teaching-card start-here-card' href='/teaching-00'>
706      <div class="start-here-icon">&#10022;</div>
707      <div class="teaching-info">
708        <div class="teaching-title" style="color: var(--berry);">Start Here</div>
709        <div class="teaching-subtitle">Leveraging This Resource</div>
710      </div>
711      <div class="teaching-download">View &rarr;</div>
712    </a>
713
714    <div style="height: 8px;"></div>
715
716    <a class='teaching-card' href='/teaching-01'>
717      <div class="teaching-number">1</div>
718      <div class="teaching-info">
719        <div class="teaching-title">Insights into Survival, Trauma & Regulation</div>
720        <div class="teaching-subtitle">Understanding the Language of Your Body</div>
721      </div>
722      <div class="teaching-download">View &rarr;</div>
723    </a>
724
725    <a class='teaching-card' href='/teaching-02'>
726      <div class="teaching-number">2</div>
727      <div class="teaching-info">
728        <div class="teaching-title">Stories & Beliefs</div>
729        <div class="teaching-subtitle">How Meaning Making Impacts Us</div>
730      </div>
731      <div class="teaching-download">View &rarr;</div>
732    </a>
733
734    <a class='teaching-card' href='/teaching-03'>
735      <div class="teaching-number">3</div>
736      <div class="teaching-info">
737        <div class="teaching-title">Consciousness Is Primary</div>
738        <div class="teaching-subtitle">The Foundation of Sovereign Choice</div>
739      </div>
740      <div class="teaching-download">View &rarr;</div>
741    </a>
742
743    <a class='teaching-card' href='/teaching-04'>
744      <div class="teaching-number">4</div>
745      <div class="teaching-info">
746        <div class="teaching-title">80/20</div>
747        <div class="teaching-subtitle">Returning to Center</div>
748      </div>
749      <div class="teaching-download">View &rarr;</div>
750    </a>
751
752    <a class='teaching-card' href='/teaching-05'>
753      <div class="teaching-number">5</div>
754      <div class="teaching-info">
755        <div class="teaching-title">Accepting What Is</div>
756        <div class="teaching-subtitle">From Resistance to Clarity</div>
757      </div>
758      <div class="teaching-download">View &rarr;</div>
759    </a>
760
761    <a class='teaching-card' href='/teaching-06'>
762      <div class="teaching-number">6</div>
763      <div class="teaching-info">
764        <div class="teaching-title">Automatic, Conscious, Simple</div>
765        <div class="teaching-subtitle">Three Ways of Meeting the Moment</div>
766      </div>
767      <div class="teaching-download">View &rarr;</div>
768    </a>
769
770    <a class='teaching-card' href='/teaching-07'>
771      <div class="teaching-number">7</div>
772      <div class="teaching-info">
773        <div class="teaching-title">Opening Our Sight</div>
774        <div class="teaching-subtitle">Expanding the Aperture of Experience</div>
775      </div>
776      <div class="teaching-download">View &rarr;</div>
777    </a>
778
779    <a class='teaching-card' href='/teaching-09'>
780      <div class="teaching-number">8</div>
781      <div class="teaching-info">
782        <div class="teaching-title">Rewriting the Code</div>
783        <div class="teaching-subtitle">Choosing New Patterns on Purpose</div>
784      </div>
785      <div class="teaching-download">View &rarr;</div>
786    </a>
787
788    <a class='teaching-card' href='/teaching-10'>
789      <div class="teaching-number">9</div>
790      <div class="teaching-info">
791        <div class="teaching-title">The S Practice</div>
792        <div class="teaching-subtitle">A Feminine Ecosystem for Being</div>
793      </div>
794      <div class="teaching-download">View &rarr;</div>
795    </a>
796
797  </section>
798
799  <!-- Bonus Resources -->
800  <div class="diamond-divider"><span>&#9830;&#xFE0E;</span></div>
801
802  <section class="bonus-section">
803    <div class="bonus-heading">Bonus Resources</div>
804
805    <a class='bonus-card' href='/completion-resources'>
806      <div class="bonus-icon">&#10022;</div>
807      <div style="flex:1;">
808        <div class="bonus-title">Completion & Ongoing Resources</div>
809        <div class="bonus-subtitle">What's Next & How to Stay Connected</div>
810      </div>
811      <div class="teaching-download">View &rarr;</div>
812    </a>
813
814  </section>
815
816  <!-- Footer -->
817  <footer class="library-footer">
818    <img src="feminine-rising-logo.png" alt="Feminine Rising" class="footer-logo"><br>
819    <div class="footer-brand">The Golden Path</div>
820    <p class="footer-copy">&copy; 2026 The Golden Path, brought to you by Feminine Rising. All rights reserved.</p>
821  </footer>
822
823</div>
824
825<script>
826// ============================================================
827// SUPABASE CLIENT (shared with the Mentorship Hub)
828// ============================================================
829const SUPABASE_URL = 'https://ttvjonqfljiinmkjbqvj.supabase.co';
830const SUPABASE_ANON_KEY = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6InR0dmpvbnFmbGppaW5ta2picXZqIiwicm9sZSI6ImFub24iLCJpYXQiOjE3NzYyNTkyNDQsImV4cCI6MjA5MTgzNTI0NH0.mQ9NUsw4cFMf2uRxPWoLl2ig04O0lHbqjx7N3hfG3iU';
831const sbClient = window.supabase ? window.supabase.createClient(SUPABASE_URL, SUPABASE_ANON_KEY) : null;
832let currentUser = null;
833
834// ============================================================
835// STEP 1 — ACCESS CODE (server-validated)
836// ============================================================
837async function checkPassword() {
838  const inputEl = document.getElementById('password-input');
839  const error = document.getElementById('password-error');
840  const btn = document.querySelector('#password-screen .password-btn');
841  const code = inputEl.value;
842
843  if (btn) { btn.disabled = true; btn.dataset.original = btn.textContent; btn.textContent = 'One moment...'; }
844
845  try {
846    const res = await fetch('/.netlify/functions/check-library-code', {
847      method: 'POST',
848      headers: { 'Content-Type': 'application/json' },
849      body: JSON.stringify({ code })
850    });
851    const data = await res.json();
852
853    if (data.ok && data.token) {
854      sessionStorage.setItem('gp_authenticated', data.token);
855      showAuthScreen();
856    } else {
857      error.classList.add('show');
858      inputEl.value = '';
859      inputEl.focus();
860    }
861  } catch (e) {
862    error.classList.add('show');
863  } finally {
864    if (btn) { btn.disabled = false; btn.textContent = btn.dataset.original || 'Continue'; }
865  }
866}
867
868document.getElementById('password-input').addEventListener('keypress', function(e) {
869  if (e.key === 'Enter') checkPassword();
870});
871
872// ============================================================
873// STEP 2 — EMAIL + PASSWORD AUTH (Supabase)
874// ============================================================
875let authMode = 'signup'; // 'signup' or 'signin'
876
877function showAuthScreen() {
878  document.getElementById('password-screen').style.display = 'none';
879  document.getElementById('reset-screen').style.display = 'none';
880  document.getElementById('library').style.display = 'none';
881  const auth = document.getElementById('auth-screen');
882  auth.style.display = 'flex';
883}
884
885function toggleAuthMode() {
886  const btn = document.getElementById('auth-send-btn');
887  const toggle = document.getElementById('auth-toggle');
888  const heading = document.getElementById('auth-heading');
889  const subtitle = document.getElementById('auth-subtitle');
890  const passInput = document.getElementById('auth-password');
891
892  if (authMode === 'signup') {
893    authMode = 'signin';
894    btn.textContent = 'Sign In';
895    toggle.textContent = 'New here? Create an account';
896    heading.textContent = 'Welcome Back';
897    subtitle.textContent = 'Sign in to enter the library.';
898    passInput.placeholder = 'Your password';
899    document.getElementById('forgot-row').style.display = 'block';
900  } else {
901    authMode = 'signup';
902    btn.textContent = 'Create My Account';
903    toggle.textContent = 'Already have an account? Sign in';
904    heading.textContent = 'Welcome, Sister';
905    subtitle.textContent = 'Create your account to enter the library.';
906    passInput.placeholder = 'Create a password';
907    document.getElementById('forgot-row').style.display = 'none';
908  }
909
910  document.getElementById('auth-message').classList.remove('show');
911}
912
913function toggleAuthPasswordVisibility() {
914  const input = document.getElementById('auth-password');
915  const icon = document.getElementById('auth-eye-icon');
916  if (!input) return;
917  const shown = input.type === 'text';
918  input.type = shown ? 'password' : 'text';
919  if (icon) icon.innerHTML = shown ? '&#128065;' : '&#128584;';
920}
921
922async function authSubmit() {
923  if (!sbClient) {
924    showAuthMessage('Connection error. Please refresh and try again.');
925    return;
926  }
927  const email = document.getElementById('auth-email').value.trim();
928  const password = document.getElementById('auth-password').value;
929  const btn = document.getElementById('auth-send-btn');
930
931  if (!email) { showAuthMessage('Please enter your email.'); return; }
932  if (!password || password.length < 6) { showAuthMessage('Password must be at least 6 characters.'); return; }
933
934  btn.disabled = true;
935  const originalText = btn.textContent;
936  btn.textContent = 'One moment...';
937
938  let result;
939  if (authMode === 'signup') {
940    result = await sbClient.auth.signUp({ email, password });
941    if (result.error && (result.error.message.includes('already registered') || result.error.message.includes('already been registered'))) {
942      result = await sbClient.auth.signInWithPassword({ email, password });
943    }
944  } else {
945    result = await sbClient.auth.signInWithPassword({ email, password });
946  }
947
948  if (result.error) {
949    showAuthMessage(result.error.message);
950    btn.disabled = false;
951    btn.textContent = originalText;
952  } else if (result.data?.user) {
953    currentUser = result.data.user;
954    // Log this library sign-in for the teacher's analytics (once per browser session)
955    sessionStorage.setItem('lib_session_logged', '1');
956    sbClient.from('library_sessions').insert({
957      user_id: currentUser.id,
958      user_email: currentUser.email
959    }).then(() => {});
960    showLibrary();
961  }
962}
963
964function showAuthMessage(msg) {
965  const el = document.getElementById('auth-message');
966  el.textContent = msg;
967  el.classList.add('show');
968  el.style.opacity = '1';
969}
970
971async function sendPasswordReset() {
972  if (!sbClient) return;
973  const email = document.getElementById('auth-email').value.trim();
974  if (!email) {
975    showAuthMessage('Please enter your email above first, then tap Forgot password.');
976    return;
977  }
978  showAuthMessage('Sending reset link...');
979  try {
980    const { error } = await sbClient.auth.resetPasswordForEmail(email, {
981      redirectTo: window.location.origin + '/library.html'
982    });
983    if (error) {
984      showAuthMessage(error.message);
985    } else {
986      const el = document.getElementById('auth-message');
987      el.textContent = 'Check your email for a password reset link.';
988      el.style.opacity = '1';
989      el.style.color = 'var(--plum)';
990    }
991  } catch (e) {
992    showAuthMessage('Could not send reset link. Please try again.');
993  }
994}
995
996document.getElementById('auth-email').addEventListener('keypress', function(e) {
997  if (e.key === 'Enter') document.getElementById('auth-password').focus();
998});
999document.getElementById('auth-password').addEventListener('keypress', function(e) {
1000  if (e.key === 'Enter') authSubmit();
1001});
1002
1003// ============================================================
1004// PASSWORD RESET FLOW (after clicking email link)
1005// ============================================================
1006function showResetScreen() {
1007  document.getElementById('password-screen').style.display = 'none';
1008  document.getElementById('auth-screen').style.display = 'none';
1009  document.getElementById('library').style.display = 'none';
1010  document.getElementById('reset-screen').style.display = 'flex';
1011}
1012
1013async function updatePasswordSubmit() {
1014  const pw = document.getElementById('reset-password').value;
1015  const pw2 = document.getElementById('reset-password-confirm').value;
1016  const msg = document.getElementById('reset-message');
1017  const btn = document.getElementById('reset-submit-btn');
1018
1019  if (!pw || pw.length < 8) { msg.textContent = 'Password must be at least 8 characters.'; msg.style.opacity = '1'; return; }
1020  if (pw !== pw2) { msg.textContent = 'Passwords do not match. Please re-type.'; msg.style.opacity = '1'; return; }
1021
1022  btn.disabled = true;
1023  btn.textContent = 'Updating...';
1024
1025  try {
1026    const { error } = await sbClient.auth.updateUser({ password: pw });
1027    if (error) {
1028      msg.textContent = error.message;
1029      msg.style.opacity = '1';
1030      btn.disabled = false;
1031      btn.textContent = 'Update Password';
1032      return;
1033    }
1034    msg.textContent = 'Password updated! Taking you to the library...';
1035    msg.style.opacity = '1';
1036    msg.style.color = 'var(--plum)';
1037    const { data: { user } } = await sbClient.auth.getUser();
1038    setTimeout(() => {
1039      if (window.history.replaceState) window.history.replaceState(null, '', window.location.pathname);
1040      if (user) { currentUser = user; showLibrary(); }
1041    }, 900);
1042  } catch (e) {
1043    msg.textContent = 'Could not update password. Please try again.';
1044    msg.style.opacity = '1';
1045    btn.disabled = false;
1046    btn.textContent = 'Update Password';
1047  }
1048}
1049
1050// ============================================================
1051// SHOW LIBRARY (after both gates pass)
1052// ============================================================
1053async function showLibrary() {
1054  document.getElementById('password-screen').style.display = 'none';
1055  document.getElementById('auth-screen').style.display = 'none';
1056  document.getElementById('reset-screen').style.display = 'none';
1057  document.getElementById('library').style.display = 'block';
1058  // Load bookmarks from Supabase, then inject UI
1059  await loadBookmarks();
1060  injectBookmarkButtons();
1061}
1062
1063// ============================================================
1064// SESSION RESTORE / RECOVERY DETECTION
1065// ============================================================
1066(async function init() {
1067  // Detect URL-based recovery flow first
1068  const urlHash = window.location.hash || '';
1069  const urlSearch = window.location.search || '';
1070  const isRecoveryUrl =
1071    urlHash.indexOf('type=recovery') !== -1 ||
1072    urlSearch.indexOf('type=recovery') !== -1 ||
1073    (urlSearch.indexOf('code=') !== -1 && urlSearch.indexOf('error') === -1);
1074
1075  if (isRecoveryUrl && sbClient) {
1076    sessionStorage.setItem('gp_authenticated', sessionStorage.getItem('gp_authenticated') || 'true');
1077    sbClient.auth.onAuthStateChange((event, session) => {
1078      if (event === 'PASSWORD_RECOVERY' || (event === 'SIGNED_IN' && session)) {
1079        showResetScreen();
1080      }
1081    });
1082    if (urlSearch.indexOf('code=') !== -1) {
1083      try {
1084        const params = new URLSearchParams(urlSearch);
1085        const code = params.get('code');
1086        if (code) await sbClient.auth.exchangeCodeForSession(code);
1087      } catch (e) {}
1088    }
1089    setTimeout(() => {
1090      if (document.getElementById('reset-screen').style.display !== 'flex') showResetScreen();
1091    }, 600);
1092    return;
1093  }
1094
1095  // Try to restore an existing Supabase session
1096  if (sbClient) {
1097    const { data: { session } } = await sbClient.auth.getSession();
1098    if (session) {
1099      currentUser = session.user;
1100      // Already signed in — but still need access code for this session
1101      const existingToken = sessionStorage.getItem('gp_authenticated');
1102      if (existingToken && (existingToken === 'true' || existingToken.startsWith('gp-'))) {
1103        // Also log this session (returning visitor) — but only once per browser-session
1104        if (!sessionStorage.getItem('lib_session_logged')) {
1105          sessionStorage.setItem('lib_session_logged', '1');
1106          sbClient.from('library_sessions').insert({
1107            user_id: currentUser.id,
1108            user_email: currentUser.email
1109          }).then(() => {});
1110        }
1111        showLibrary();
1112        return;
1113      }
1114    }
1115  }
1116
1117  // Check if access code was already entered this session
1118  const existingToken = sessionStorage.getItem('gp_authenticated');
1119  if (existingToken && (existingToken === 'true' || existingToken.startsWith('gp-'))) {
1120    // Code is good — go to auth (or library if already signed in)
1121    if (currentUser) {
1122      showLibrary();
1123    } else {
1124      showAuthScreen();
1125    }
1126  }
1127  // Otherwise the password-screen is already visible by default
1128})();
1129
1130// ============================================================
1131// BOOKMARKS / FAVORITES (per-user, stored in Supabase)
1132// ============================================================
1133let favorites = {}; // map: { teaching_key: true }
1134let favoritesOnly = false;
1135
1136async function loadBookmarks() {
1137  favorites = {};
1138  if (!sbClient || !currentUser) return;
1139  const { data } = await sbClient
1140    .from('library_bookmarks')
1141    .select('teaching_key')
1142    .eq('user_id', currentUser.id);
1143  if (data) data.forEach(b => { favorites[b.teaching_key] = true; });
1144}
1145
1146async function toggleBookmark(event, key) {
1147  event.preventDefault();
1148  event.stopPropagation();
1149  if (!sbClient || !currentUser) return;
1150
1151  const isCurrentlyFav = !!favorites[key];
1152  const btn = event.currentTarget;
1153
1154  // Optimistic UI update
1155  if (isCurrentlyFav) {
1156    delete favorites[key];
1157    if (btn) {
1158      btn.classList.remove('bookmarked');
1159      btn.innerHTML = '&#9825;';
1160      btn.setAttribute('aria-label', 'Add to favorites');
1161      btn.setAttribute('title', 'Add to favorites');
1162    }
1163    await sbClient.from('library_bookmarks').delete()
1164      .eq('user_id', currentUser.id)
1165      .eq('teaching_key', key);
1166  } else {
1167    favorites[key] = true;
1168    if (btn) {
1169      btn.classList.add('bookmarked');
1170      btn.innerHTML = '&#9829;';
1171      btn.setAttribute('aria-label', 'Remove from favorites');
1172      btn.setAttribute('title', 'Remove from favorites');
1173    }
1174    await sbClient.from('library_bookmarks').insert({
1175      user_id: currentUser.id,
1176      teaching_key: key
1177    });
1178  }
1179
1180  if (favoritesOnly) applyFavoritesFilter();
1181}
1182
1183function injectBookmarkButtons() {
1184  document.querySelectorAll('.teaching-card').forEach(card => {
1185    if (card.querySelector('.bookmark-btn')) return;
1186    const href = card.getAttribute('href') || '';
1187    const key = href.replace(/[^a-z0-9]/gi, '_');
1188    if (!key) return;
1189    const isFav = !!favorites[key];
1190
1191    const btn = document.createElement('button');
1192    btn.className = 'bookmark-btn' + (isFav ? ' bookmarked' : '');
1193    btn.innerHTML = isFav ? '&#9829;' : '&#9825;';
1194    btn.setAttribute('aria-label', isFav ? 'Remove from favorites' : 'Add to favorites');
1195    btn.setAttribute('title', isFav ? 'Remove from favorites' : 'Add to favorites');
1196    btn.onclick = function(e) { toggleBookmark(e, key); };
1197    card.dataset.favKey = key;
1198    const dl = card.querySelector('.teaching-download');
1199    if (dl) {
1200      card.insertBefore(btn, dl);
1201    } else {
1202      card.appendChild(btn);
1203    }
1204  });
1205}
1206
1207function toggleFavoritesFilter() {
1208  favoritesOnly = !favoritesOnly;
1209  const btn = document.getElementById('fav-filter-btn');
1210  const icon = document.getElementById('fav-filter-icon');
1211  const label = document.getElementById('fav-filter-label');
1212  if (favoritesOnly) {
1213    btn.classList.add('active');
1214    icon.innerHTML = '&#9829;';
1215    label.textContent = 'Showing Favorites';
1216  } else {
1217    btn.classList.remove('active');
1218    icon.innerHTML = '&#9825;';
1219    label.textContent = 'Show Favorites';
1220  }
1221  applyFavoritesFilter();
1222}
1223
1224function applyFavoritesFilter() {
1225  document.querySelectorAll('.teaching-card').forEach(card => {
1226    const key = card.dataset.favKey;
1227    if (!favoritesOnly) {
1228      card.classList.remove('hidden-by-filter');
1229    } else {
1230      if (key && favorites[key]) {
1231        card.classList.remove('hidden-by-filter');
1232      } else {
1233        card.classList.add('hidden-by-filter');
1234      }
1235    }
1236  });
1237}
1238</script>
1238
1239
1240</body>
1241</html>

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.