ReviewOS

also looking at this

stacks/lastsoulultra

LSU's own coaching surface, and what auditing the site turned up

#12
Merged glennmichael123 wants to merge claude/last-soul-ultra-web-6e0718 into main
86 files +3943 -1190

Review threads live on the whole diff, not on one commit, so none are shown here - a thread's line means something in the branch's final form, and painting it into an intermediate step would put it on code it is not about.

public/assets/styles/production/coaching.cssmodified+11-0
Changes to public/assets/styles/production/coaching.css
@@ -74,6 +74,16 @@
7474.coaching-surface .coach-offer-trial {display:block;margin-top:8px;color:var(--lsu-dim-3);font:400 13px/1.4 var(--lsu-body)}
7575.coaching-surface .coach-offer-note {margin:14px 0 0;color:var(--lsu-dim-3);font:400 13px/1.5 var(--lsu-body)}
7676
77/* The hub's index of modules. A ruled list rather than a card grid: eight
78 cards is a wall, and the sentence beside each name is the part that is
79 worth reading. The whole row is the target, not the word. */
80.coaching-surface .coach-index {display:grid;margin:clamp(34px,4vw,56px) 0 0;padding:0;list-style:none;border-top:var(--coach-rule)}
81.coaching-surface .coach-index li {border-bottom:var(--coach-rule)}
82.coaching-surface .coach-index a {display:grid;grid-template-columns:minmax(0,15rem) minmax(0,1fr);gap:clamp(12px,3vw,40px);align-items:baseline;padding:clamp(18px,2.2vw,26px) 0;text-decoration:none}
83.coaching-surface .coach-index a:hover .coach-index-label {color:var(--lsu-red)}
84.coaching-surface .coach-index-label {font:400 clamp(20px,2.2vw,28px)/1.1 var(--lsu-display);text-transform:uppercase;color:var(--lsu-white);transition:color .18s}
85.coaching-surface .coach-index-summary {max-width:60ch;color:var(--lsu-dim-1);font:400 15px/1.65 var(--lsu-body)}
86
7787/* Nothing published yet. The honest state, and the one that ships today. */
7888.coaching-surface .coach-empty {margin:0 0 clamp(40px,5vw,72px);padding:clamp(30px,5vw,56px);border:var(--coach-rule);background:var(--lsu-card)}
7989.coaching-surface .coach-empty h2 {margin:0;font:400 clamp(24px,3vw,34px)/1.1 var(--lsu-display);text-transform:uppercase}
@@ -85,6 +95,7 @@
8595
8696@media (max-width:760px) {
8797 .coaching-surface .coach-offer {grid-template-columns:minmax(0,1fr);gap:18px}
98 .coaching-surface .coach-index a {grid-template-columns:minmax(0,1fr);gap:8px}
8899 .coaching-surface .coach-offer-price {text-align:left}
89100 .coaching-surface .coach-panel {min-height:520px}
90101}
resources/assets/styles/site/coaching.cssmodified+11-0
Changes to resources/assets/styles/site/coaching.css
@@ -74,6 +74,16 @@
7474.coaching-surface .coach-offer-trial {display:block;margin-top:8px;color:var(--lsu-dim-3);font:400 13px/1.4 var(--lsu-body)}
7575.coaching-surface .coach-offer-note {margin:14px 0 0;color:var(--lsu-dim-3);font:400 13px/1.5 var(--lsu-body)}
7676
77/* The hub's index of modules. A ruled list rather than a card grid: eight
78 cards is a wall, and the sentence beside each name is the part that is
79 worth reading. The whole row is the target, not the word. */
80.coaching-surface .coach-index {display:grid;margin:clamp(34px,4vw,56px) 0 0;padding:0;list-style:none;border-top:var(--coach-rule)}
81.coaching-surface .coach-index li {border-bottom:var(--coach-rule)}
82.coaching-surface .coach-index a {display:grid;grid-template-columns:minmax(0,15rem) minmax(0,1fr);gap:clamp(12px,3vw,40px);align-items:baseline;padding:clamp(18px,2.2vw,26px) 0;text-decoration:none}
83.coaching-surface .coach-index a:hover .coach-index-label {color:var(--lsu-red)}
84.coaching-surface .coach-index-label {font:400 clamp(20px,2.2vw,28px)/1.1 var(--lsu-display);text-transform:uppercase;color:var(--lsu-white);transition:color .18s}
85.coaching-surface .coach-index-summary {max-width:60ch;color:var(--lsu-dim-1);font:400 15px/1.65 var(--lsu-body)}
86
7787/* Nothing published yet. The honest state, and the one that ships today. */
7888.coaching-surface .coach-empty {margin:0 0 clamp(40px,5vw,72px);padding:clamp(30px,5vw,56px);border:var(--coach-rule);background:var(--lsu-card)}
7989.coaching-surface .coach-empty h2 {margin:0;font:400 clamp(24px,3vw,34px)/1.1 var(--lsu-display);text-transform:uppercase}
@@ -85,6 +95,7 @@
8595
8696@media (max-width:760px) {
8797 .coaching-surface .coach-offer {grid-template-columns:minmax(0,1fr);gap:18px}
98 .coaching-surface .coach-index a {grid-template-columns:minmax(0,1fr);gap:8px}
8899 .coaching-surface .coach-offer-price {text-align:left}
89100 .coaching-surface .coach-panel {min-height:520px}
90101}
resources/components/CoachingIndex.stxadded+22-0
Changes to resources/components/CoachingIndex.stx
@@ -0,0 +1,22 @@
1<script server>
2import { enabledModules, modulePath } from '../data/coaching'
3import { loadBrand } from '../functions/coaching-source'
4
5/* The hub's version of the nav: the same modules, but with the sentence that
6 says what each one is for. A row of eight words is navigation; this is the
7 page that has to explain itself. */
8const indexBrand = await loadBrand()
9const indexModules = enabledModules(indexBrand?.modules)
10</script>
11@if(indexModules.length > 1)
12<ul class="coach-index">
13 @foreach(indexModules as item)
14 <li>
15 <a href="">
16 <span class="coach-index-label">{{ item.label }}</span>
17 <span class="coach-index-summary">{{ item.summary }}</span>
18 </a>
19 </li>
20 @endforeach
21</ul>
22@endif
resources/views/coaching.stxmodified+13-5
Changes to resources/views/coaching.stx
@@ -1,10 +1,14 @@
11@extends('layouts/LSU')
22@section('content')
33<script server>
4import { coachingStyles } from '~/resources/data/coaching'
5
46// The home, race-entry and next-loop sheets are each suffixed with their own
5// page scope, so none of their rules could ever match here. The coaching styles
6// live in the site-wide stx-site.css that the head always loads.
7const currentPage = { title: 'Coaching - Last Soul Ultra', description: 'Send a voice message after your run and an AI rebuilds next week around what you said, inside a coach\'s method.', styles: ['/assets/styles/production/base.css'] }
7// page scope, so none of their rules could ever match here. This page's own
8// rules live in the site-wide stx-site.css that the head always loads; the
9// storefront and module index it now carries are styled by the surface sheet,
10// which the eight module routes load too.
11const currentPage = { title: 'Coaching - Last Soul Ultra', description: 'Send a voice message after your run and an AI rebuilds next week around what you said, inside a coach\'s method.', styles: coachingStyles }
812const canonicalPath = '/coaching'
913</script>
1014<div class="coaching-page">
@@ -84,8 +88,12 @@ const canonicalPath = '/coaching'
8488
8589 <section id="training">
8690 <div class="coaching-head">
87 <h2 class="h2-sm">Not open yet.<br><span class="accent">It opens here.</span></h2>
88 <p>No method has been published and no price has been set. When the first tier opens, it appears in this panel.</p>
91 <h2 class="h2-sm">What is open.<br><span class="accent">And where it runs.</span></h2>
92 <p>The tiers a coach has published, then the eight panels your training lives in once you are in one.</p>
93 </div>
94 <div class="coaching-surface">
95 <CoachingOffers />
96 <CoachingIndex />
8997 </div>
9098 <div class="coaching-portal"><CoachingPortal /></div>
9199 </section>