diff --git a/supabase/README.md b/supabase/README.md
index d8eb45e..799c445 100644
--- a/supabase/README.md
+++ b/supabase/README.md
@@ -24,6 +24,7 @@ The full schema history for the project, in apply order:
| `20260715010000_college_ingest_runs` | `college_ingest_runs` audit log for the Scorecard ingest. |
| `20260717000000_college_student_body` | Adds `student_body` jsonb (diversity / retention / women / first-gen) to `colleges` for the Discover detail popup. |
| `20260915000000_remove_paid_and_political_scholarships` | Archives nine curated scholarships: six that charge an application/entry fee, three political-advocacy essay contests. See `seed.sql`'s curation rules. |
+| `20260930000000_college_aid_guarantees` | Adds `aid_guarantee*` columns to `colleges` (with a CHECK that the four text fields come together) and backfills 40 schools' income guarantees across 54 campus rows (Harvard, Go Blue Guarantee, Blue and Gold, …), checked 2026-09-30. The only source for guarantees; correct one with a new migration. |
### Notes
diff --git a/supabase/migrations/20260930000000_college_aid_guarantees.sql b/supabase/migrations/20260930000000_college_aid_guarantees.sql
new file mode 100644
index 0000000..c03cc98
--- /dev/null
+++ b/supabase/migrations/20260930000000_college_aid_guarantees.sql
@@ -0,0 +1,290 @@
+-- Income guarantees from each school's own financial aid program.
+--
+-- A growing number of colleges promise free tuition (sometimes the full cost)
+-- below a family income: Harvard under $200,000, Michigan's Go Blue Guarantee,
+-- UC's Blue and Gold plan. Every one of them depends on the student finishing
+-- that school's aid steps on time, so the app shows the guarantee next to the
+-- school and turns it into a task on the school's application page.
+--
+-- No public dataset carries these. The College Scorecard has nothing on them
+-- and neither does the Common Data Set, so each row below was read off the
+-- school's own site and checked on 2026-09-30. Which schools need the CSS
+-- Profile was checked against College Board's 2027–28 participating list.
+-- Thresholds that change for students entering in fall 2027 carry the fall 2027
+-- figure: that is this year's seniors.
+--
+-- One guarantee per school, so plain columns rather than a side table. All are
+-- null for a school without one, and null means "none we know of", never "this
+-- school offers nothing".
+--
+-- From here on this table is the only source: the app reads guarantees from it
+-- (and copies the short form onto each saved school for its task list). To
+-- change one, write a new migration with the corrected row and checked date.
+
+alter table public.colleges
+ add column if not exists aid_guarantee text,
+ add column if not exists aid_guarantee_residents text,
+ add column if not exists aid_guarantee_needs_css boolean,
+ add column if not exists aid_guarantee_detail text,
+ add column if not exists aid_guarantee_action text,
+ add column if not exists aid_guarantee_url text,
+ add column if not exists aid_guarantee_checked_on date;
+
+comment on column public.colleges.aid_guarantee is
+ 'Name or one-line summary of the school''s income guarantee (e.g. ''Go Blue Guarantee''). Null means none we know of.';
+comment on column public.colleges.aid_guarantee_residents is
+ 'Who the guarantee is limited to (e.g. ''Michigan residents''). Null when it is open to every U.S. student.';
+comment on column public.colleges.aid_guarantee_needs_css is
+ 'True when getting the guarantee takes the CSS Profile. Drives the CSS task on public schools, which otherwise only private ones get.';
+comment on column public.colleges.aid_guarantee_detail is
+ 'Who qualifies and what is covered, in plain language.';
+comment on column public.colleges.aid_guarantee_action is
+ 'What the student must file, and by when, to get it.';
+comment on column public.colleges.aid_guarantee_url is
+ 'The school''s own page for the guarantee. The source for the row.';
+comment on column public.colleges.aid_guarantee_checked_on is
+ 'When the row was last checked against aid_guarantee_url. These change most years.';
+
+-- Backfill. Keyed on scorecard_id. Rows were found by website domain and then
+-- checked by hand: satellite campuses a program covers are in (all six Ohio
+-- State campuses, Emory's Oxford College), while graduate schools and online
+-- divisions that share a parent's domain are out (Teachers College, Weill
+-- Cornell, Texas A&M Health Science Center, UF Online, Notre Dame's second
+-- non-degree row).
+with guarantees(scorecard_id, aid_guarantee, aid_guarantee_residents, aid_guarantee_needs_css,
+ aid_guarantee_detail, aid_guarantee_action, aid_guarantee_url) as (values
+ (166027, 'Free tuition under $200K', null, true,
+ 'Tuition is covered for families earning $200,000 or less. Under $100,000, families pay nothing at all.',
+ 'File the FAFSA and the CSS Profile by the school’s financial aid deadline.',
+ 'https://college.harvard.edu/financial-aid'),
+ (166683, 'Free tuition under $200K', null, true,
+ 'Tuition is covered for families earning under $200,000. Under $100,000, families pay nothing at all.',
+ 'File the FAFSA and the CSS Profile by the school’s financial aid deadline.',
+ 'https://news.mit.edu/2024/mit-tuition-undergraduates-family-income-1120'),
+ (186131, 'Free tuition under $250K', null, false,
+ 'Most families earning up to $250,000 pay no tuition. Up to $150,000, most pay nothing at all.',
+ 'File the FAFSA and Princeton’s own financial aid application.',
+ 'https://www.princeton.edu/news/2025/08/07/princeton-enhances-financial-aid-again-it-welcomes-class-2029-which-includes'),
+ (130794, 'Free tuition under $200K', null, true,
+ 'From 2026–27, tuition is covered for families earning under $200,000. Under $100,000, families pay nothing at all.',
+ 'File the FAFSA and the CSS Profile by the school’s financial aid deadline.',
+ 'https://news.yale.edu/2026/01/27/yale-offer-free-tuition-families-incomes-below-200000'),
+ (215062, 'Quaker Commitment', null, true,
+ 'Full tuition for most families earning up to $200,000. Under $75,000, most get the full cost covered.',
+ 'File the FAFSA and the CSS Profile by the school’s financial aid deadline.',
+ 'https://www.upenn.edu/pennforward/penn-quaker-commitment'),
+ (190150, 'Free tuition under $150K', null, true,
+ 'Columbia College and Columbia Engineering are tuition-free for families earning under $150,000. Under $66,000, parents pay nothing.',
+ 'File the FAFSA and the CSS Profile by the school’s financial aid deadline.',
+ 'https://cc-seas.financialaid.columbia.edu/how/aid/works'),
+ (217156, 'Free tuition under $125K', null, true,
+ 'Full tuition is covered for families earning $125,000 or less. Under $60,000, all direct costs are covered.',
+ 'File the FAFSA and the CSS Profile by the school’s financial aid deadline.',
+ 'https://www.brown.edu/news/2026-02-09/fy27-tuition-fees-salaries'),
+ (182670, 'Free tuition under $175K', null, true,
+ 'Families earning under $125,000 pay no parent contribution. From $125,000 to $175,000, tuition is covered.',
+ 'File the FAFSA and the CSS Profile by the school’s financial aid deadline.',
+ 'https://financialaid.dartmouth.edu/how-aid-works/how-much-help-will-i-get'),
+ (190415, 'Free tuition under $125K', null, true,
+ 'Tuition is covered for families earning up to $125,000. Up to $75,000, the full cost is covered.',
+ 'File the FAFSA and the CSS Profile by the school’s financial aid deadline.',
+ 'https://news.cornell.edu/stories/2026/03/board-trustees-approves-2026-27-budget-parameters'),
+ (243744, 'Free tuition under $150K', null, true,
+ 'Tuition is free for families earning under $150,000. Under $100,000, tuition, housing and food are free.',
+ 'File the FAFSA and the CSS Profile by the school’s financial aid deadline.',
+ 'https://admission.stanford.edu/afford/'),
+ (110404, 'Free tuition under $200K', null, true,
+ 'Tuition is covered for families earning under $200,000. Under $100,000, the full cost is covered.',
+ 'File the FAFSA and the CSS Profile by the school’s financial aid deadline.',
+ 'https://www.finaid.caltech.edu/'),
+ (162928, 'Free tuition under $200K', null, true,
+ 'From 2026–27, tuition is free for families earning up to $200,000. Up to $100,000, families pay nothing.',
+ 'File the FAFSA and the CSS Profile by the school’s financial aid deadline.',
+ 'https://sfs.jhu.edu/tuition-promise/'),
+ (147767, 'Pay nothing under $70K', null, true,
+ 'Most families earning under $70,000 attend at no cost. Northwestern is fundraising to make it tuition-free under $150,000, but that is a goal, not yet a promise.',
+ 'File the FAFSA and the CSS Profile by the school’s financial aid deadline.',
+ 'https://undergradaid.northwestern.edu/'),
+ (144050, 'Free tuition under $250K', null, false,
+ 'For students starting in fall 2027, tuition is free for families earning up to $250,000. Up to $125,000, tuition, housing, meals and fees are covered.',
+ 'File the FAFSA and the school’s required aid forms by its deadline. Its aid page lists them.',
+ 'https://www.uchicago.edu/admissions/affordability'),
+ (221999, 'Free tuition under $200K', null, true,
+ 'Opportunity Vanderbilt covers full tuition for families earning $200,000 or less, starting with students who enter in fall 2027.',
+ 'File the FAFSA and the CSS Profile by the school’s financial aid deadline.',
+ 'https://admissions.vanderbilt.edu/affordability/opportunity-vanderbilt/'),
+ (227757, 'Free tuition under $200K', null, true,
+ 'For students entering in fall 2027, tuition is free for families earning up to $200,000. Under $100,000, tuition, fees, housing and food are covered.',
+ 'File the FAFSA and the CSS Profile by the school’s financial aid deadline.',
+ 'https://financialaid.rice.edu/rice-investment'),
+ (487092, 'Free tuition under $200K', null, true,
+ 'From fall 2026, Emory Advantage Plus makes Emory tuition-free for U.S. students from families earning $200,000 or less.',
+ 'File the FAFSA and the CSS Profile by the school’s financial aid deadline.',
+ 'https://studentaid.emory.edu/undergraduate/types/grants-scholarships/emory-grants/emory-advantage.html'),
+ (139658, 'Free tuition under $200K', null, true,
+ 'From fall 2026, Emory Advantage Plus makes Emory tuition-free for U.S. students from families earning $200,000 or less.',
+ 'File the FAFSA and the CSS Profile by the school’s financial aid deadline.',
+ 'https://studentaid.emory.edu/undergraduate/types/grants-scholarships/emory-grants/emory-advantage.html'),
+ (168148, 'Free tuition under $150K', null, true,
+ 'From fall 2026, the Tufts Tuition Pact makes Tufts tuition-free for U.S. families earning less than $150,000.',
+ 'File the FAFSA and the CSS Profile by the school’s financial aid deadline.',
+ 'https://now.tufts.edu/2025/09/09/tufts-will-be-tuition-free-us-families-earning-less-150000'),
+ (152080, 'Free tuition under $150K', null, true,
+ 'From 2026–27, tuition is covered for families earning under $150,000, and half of tuition under $200,000.',
+ 'File the FAFSA and the CSS Profile by the school’s financial aid deadline.',
+ 'https://financialaid.nd.edu/costs-and-affordability/'),
+ (164988, 'BU Promise', null, true,
+ 'From 2026–27, full tuition is covered for families earning under $200,000, with the parent share capped at $20,000 a year. Families earning $75,000 or less pay nothing.',
+ 'File the FAFSA and the CSS Profile by the school’s financial aid deadline.',
+ 'https://www.bu.edu/articles/2026/new-financial-aid-program-covers-tuition-for-certain-families/'),
+ (123961, 'Free tuition under $80K', null, true,
+ 'Tuition is free for students who start as first-years from families earning $80,000 or less.',
+ 'File the FAFSA and the CSS Profile by the school’s financial aid deadline.',
+ 'https://affordability.usc.edu/'),
+ (190099, 'Free tuition under $175K', null, true,
+ 'From fall 2026, the Colgate Commitment makes tuition free for families earning up to $175,000, with no loans up to $200,000.',
+ 'File the FAFSA and the CSS Profile by the school’s financial aid deadline.',
+ 'https://www.colgate.edu/admission-aid/financial-aid/colgate-commitment'),
+ (234207, 'Free tuition under $200K', null, true,
+ 'The W&L Promise makes tuition free for families earning under $200,000, starting with students who enter in fall 2027. Under $75,000, housing and food are covered too.',
+ 'File the FAFSA and the CSS Profile by the school’s financial aid deadline.',
+ 'https://www.wlu.edu/admissions/financial-aid/the-w-l-promise'),
+ (164465, 'Free tuition under $141K', null, true,
+ 'Most students from families earning under $141,000 receive a scholarship covering tuition. Under $67,500, most get tuition, housing and meals covered.',
+ 'File the FAFSA and the CSS Profile by the school’s financial aid deadline.',
+ 'https://www.amherst.edu/admission/financial_aid'),
+ (198419, 'Free tuition under $150K', 'North and South Carolina residents', true,
+ 'Full tuition for North and South Carolina residents from families earning $150,000 or less. Up to $65,000, housing and meals are covered too.',
+ 'File the FAFSA and the CSS Profile by the school’s financial aid deadline.',
+ 'https://financialaid.duke.edu/initiative-students-carolinas/'),
+ (199847, 'Free tuition under $200K', 'North Carolina residents', true,
+ 'From fall 2026, North Carolina students from families earning $200,000 or less attend tuition-free. At $100,000 or less, housing and food are covered too. From $200,001 to $300,000, half of tuition is covered.',
+ 'File the FAFSA and the CSS Profile by the school’s financial aid deadline.',
+ 'https://financialaid.wfu.edu/types-of-aid/ncgateway-to-wfu/'),
+ (179867, 'WashU Pledge', 'Missouri and southern Illinois students', true,
+ 'Tuition, fees, housing and food for first-year students from Missouri and southern Illinois whose families earn $75,000 or less.',
+ 'File the FAFSA and the CSS Profile by the school’s financial aid deadline.',
+ 'https://financialaid.washu.edu/how-washu-helps/washu-pledge/'),
+ (170976, 'Go Blue Guarantee', 'Michigan residents', true,
+ 'Free tuition for Michigan residents with family income and assets of $125,000 or less.',
+ 'No separate application, but file the FAFSA and the CSS Profile by March 31.',
+ 'https://finaid.umich.edu/apply-aid/new-undergraduates/michigan-residents/go-blue-guarantee-eligibility'),
+ (110635, 'Blue and Gold Opportunity Plan', 'California residents', false,
+ 'Most California families earning up to $100,000 get UC tuition covered.',
+ 'No separate application. File the FAFSA or the California Dream Act Application by March 2.',
+ 'https://admission.universityofcalifornia.edu/tuition-financial-aid/types-of-aid/blue-and-gold-opportunity-plan.html'),
+ (110662, 'Blue and Gold Opportunity Plan', 'California residents', false,
+ 'Most California families earning up to $100,000 get UC tuition covered.',
+ 'No separate application. File the FAFSA or the California Dream Act Application by March 2.',
+ 'https://admission.universityofcalifornia.edu/tuition-financial-aid/types-of-aid/blue-and-gold-opportunity-plan.html'),
+ (110680, 'Blue and Gold Opportunity Plan', 'California residents', false,
+ 'Most California families earning up to $100,000 get UC tuition covered.',
+ 'No separate application. File the FAFSA or the California Dream Act Application by March 2.',
+ 'https://admission.universityofcalifornia.edu/tuition-financial-aid/types-of-aid/blue-and-gold-opportunity-plan.html'),
+ (110653, 'Blue and Gold Opportunity Plan', 'California residents', false,
+ 'Most California families earning up to $100,000 get UC tuition covered.',
+ 'No separate application. File the FAFSA or the California Dream Act Application by March 2.',
+ 'https://admission.universityofcalifornia.edu/tuition-financial-aid/types-of-aid/blue-and-gold-opportunity-plan.html'),
+ (110644, 'Blue and Gold Opportunity Plan', 'California residents', false,
+ 'Most California families earning up to $100,000 get UC tuition covered.',
+ 'No separate application. File the FAFSA or the California Dream Act Application by March 2.',
+ 'https://admission.universityofcalifornia.edu/tuition-financial-aid/types-of-aid/blue-and-gold-opportunity-plan.html'),
+ (110705, 'Blue and Gold Opportunity Plan', 'California residents', false,
+ 'Most California families earning up to $100,000 get UC tuition covered.',
+ 'No separate application. File the FAFSA or the California Dream Act Application by March 2.',
+ 'https://admission.universityofcalifornia.edu/tuition-financial-aid/types-of-aid/blue-and-gold-opportunity-plan.html'),
+ (110714, 'Blue and Gold Opportunity Plan', 'California residents', false,
+ 'Most California families earning up to $100,000 get UC tuition covered.',
+ 'No separate application. File the FAFSA or the California Dream Act Application by March 2.',
+ 'https://admission.universityofcalifornia.edu/tuition-financial-aid/types-of-aid/blue-and-gold-opportunity-plan.html'),
+ (110671, 'Blue and Gold Opportunity Plan', 'California residents', false,
+ 'Most California families earning up to $100,000 get UC tuition covered.',
+ 'No separate application. File the FAFSA or the California Dream Act Application by March 2.',
+ 'https://admission.universityofcalifornia.edu/tuition-financial-aid/types-of-aid/blue-and-gold-opportunity-plan.html'),
+ (445188, 'Blue and Gold Opportunity Plan', 'California residents', false,
+ 'Most California families earning up to $100,000 get UC tuition covered.',
+ 'No separate application. File the FAFSA or the California Dream Act Application by March 2.',
+ 'https://admission.universityofcalifornia.edu/tuition-financial-aid/types-of-aid/blue-and-gold-opportunity-plan.html'),
+ (228778, 'Texas Advance Commitment', 'Texas residents', false,
+ 'Full tuition for Texas residents with family income up to $100,000, and help with tuition up to $125,000.',
+ 'File the FAFSA or TASFA by UT’s priority deadline.',
+ 'https://admissions.utexas.edu/cost-aid/financial-aid/texas-advance-commitment/'),
+ (228723, 'Aggie Assurance', 'Texas residents', false,
+ 'From fall 2026, free tuition and fees for Texas residents with family income and assets under $100,000.',
+ 'File the FAFSA or TASFA by the state priority deadline.',
+ 'https://stories.tamu.edu/news/2026/02/20/texas-am-university-reinforces-commitment-to-affordable-education-with-expanded-aid/'),
+ (234076, 'AccessUVA', 'Virginia residents', true,
+ 'Grants cover at least tuition and fees for Virginia families earning $100,000 or less. At $50,000 or less, housing and dining are covered too.',
+ 'File the FAFSA and the CSS Profile by the school’s financial aid deadline.',
+ 'https://news.virginia.edu/content/uva-expands-financial-aid-program-virginia-families'),
+ (199120, 'Free tuition under $80K', 'North Carolina residents', true,
+ 'Tuition and mandatory fees are covered for in-state students from families earning less than $80,000.',
+ 'File the FAFSA and the CSS Profile by the school’s financial aid deadline.',
+ 'https://studentaid.unc.edu/tar-heel-guarantee/'),
+ (145637, 'Illinois Commitment', 'Illinois residents', false,
+ 'Free tuition and campus fees for Illinois residents with family income and assets of $75,000 or less each.',
+ 'File the FAFSA before March 15.',
+ 'https://www.osfa.illinois.edu/illinois-commitment/'),
+ (240444, 'Bucky’s Tuition Promise', 'Wisconsin residents', false,
+ 'Free tuition and fees for Wisconsin residents with a household income (AGI) of $65,000 or less. Assets are not counted.',
+ 'No separate application. File the FAFSA by the December 1 priority deadline.',
+ 'https://financialaid.wisc.edu/types-of-aid/tuition-promise/'),
+ (204680, 'Buckeye Opportunity Program', 'Ohio residents', false,
+ 'Tuition and mandatory fees are covered for Ohio residents who qualify for a Pell Grant.',
+ 'File the FAFSA by Ohio State’s Feb 1 priority date, every year.',
+ 'https://news.osu.edu/buckeye-opportunity-program-helps-keep-college-affordable-at-ohio-state/'),
+ (204796, 'Buckeye Opportunity Program', 'Ohio residents', false,
+ 'Tuition and mandatory fees are covered for Ohio residents who qualify for a Pell Grant.',
+ 'File the FAFSA by Ohio State’s Feb 1 priority date, every year.',
+ 'https://news.osu.edu/buckeye-opportunity-program-helps-keep-college-affordable-at-ohio-state/'),
+ (204662, 'Buckeye Opportunity Program', 'Ohio residents', false,
+ 'Tuition and mandatory fees are covered for Ohio residents who qualify for a Pell Grant.',
+ 'File the FAFSA by Ohio State’s Feb 1 priority date, every year.',
+ 'https://news.osu.edu/buckeye-opportunity-program-helps-keep-college-affordable-at-ohio-state/'),
+ (204671, 'Buckeye Opportunity Program', 'Ohio residents', false,
+ 'Tuition and mandatory fees are covered for Ohio residents who qualify for a Pell Grant.',
+ 'File the FAFSA by Ohio State’s Feb 1 priority date, every year.',
+ 'https://news.osu.edu/buckeye-opportunity-program-helps-keep-college-affordable-at-ohio-state/'),
+ (204699, 'Buckeye Opportunity Program', 'Ohio residents', false,
+ 'Tuition and mandatory fees are covered for Ohio residents who qualify for a Pell Grant.',
+ 'File the FAFSA by Ohio State’s Feb 1 priority date, every year.',
+ 'https://news.osu.edu/buckeye-opportunity-program-helps-keep-college-affordable-at-ohio-state/'),
+ (204705, 'Buckeye Opportunity Program', 'Ohio residents', false,
+ 'Tuition and mandatory fees are covered for Ohio residents who qualify for a Pell Grant.',
+ 'File the FAFSA by Ohio State’s Feb 1 priority date, every year.',
+ 'https://news.osu.edu/buckeye-opportunity-program-helps-keep-college-affordable-at-ohio-state/'),
+ (163286, 'Terrapin Commitment', 'Maryland residents', false,
+ 'Tuition and fees are covered for Maryland residents who are Pell-eligible or from families earning $75,000 or less.',
+ 'File the FAFSA by March 1, every year.',
+ 'https://financialaid.umd.edu/terrapin-commitment'),
+ (139755, 'Tech Promise', 'Georgia residents', true,
+ 'A debt-free degree for Georgia residents from families earning under $55,500.',
+ 'File the FAFSA and the CSS Profile by the school’s financial aid deadline.',
+ 'https://www.techpromise.em.gatech.edu/'),
+ (236948, 'Husky Promise', 'Washington residents', false,
+ 'Full tuition and standard fees for Washington residents who qualify for a Pell Grant.',
+ 'File the FAFSA or WASFA by UW’s priority date.',
+ 'https://www.washington.edu/huskypromise/'),
+ (134130, 'Machen Florida Opportunity Scholars', null, false,
+ 'Full need met with grants and scholarships for first-generation students with family income under $55,000 and assets under $35,000.',
+ 'File the FAFSA by UF’s priority deadline.',
+ 'https://www.sfa.ufl.edu/mfos')
+)
+update public.colleges c set
+ aid_guarantee = v.aid_guarantee,
+ aid_guarantee_residents = v.aid_guarantee_residents,
+ aid_guarantee_needs_css = v.aid_guarantee_needs_css,
+ aid_guarantee_detail = v.aid_guarantee_detail,
+ aid_guarantee_action = v.aid_guarantee_action,
+ aid_guarantee_url = v.aid_guarantee_url,
+ aid_guarantee_checked_on = date '2026-09-30'
+from guarantees v
+where c.scorecard_id = v.scorecard_id;
+
+-- A guarantee is the four text fields together or none of them. A partial row
+-- would show a guarantee with no steps to get it, so it is refused at the
+-- database rather than hidden in the app. Residents may be null on its own.
+alter table public.colleges drop constraint if exists colleges_aid_guarantee_complete;
+alter table public.colleges add constraint colleges_aid_guarantee_complete check (
+ num_nulls(aid_guarantee, aid_guarantee_detail, aid_guarantee_action, aid_guarantee_url) in (0, 4)
+);
diff --git a/web/src/components/AidGuideSections.tsx b/web/src/components/AidGuideSections.tsx
new file mode 100644
index 0000000..84bed4f
--- /dev/null
+++ b/web/src/components/AidGuideSections.tsx
@@ -0,0 +1,268 @@
+import { useEffect, useState, type ReactNode } from 'react'
+import { C, MODULE_COLORS } from '../lib/designTokens'
+import { fetchAllGuarantees, type AidGuarantee, type GuaranteeList } from '../lib/aidColleges'
+import { formatCollegeDate, parseIsoDay } from '../data/applicationDeadlines'
+import { SecLabel } from './moduleUI'
+import {
+ AID_FACTS_AS_OF,
+ guaranteeLabel,
+ MAJOR_PROGRAMS,
+ SCHOLARSHIP_CATEGORIES,
+ STATE_GRANTS,
+ type AidProgram,
+ type GrantState,
+} from '../data/aidPrograms'
+
+const MC = MODULE_COLORS.financialAid
+
+/**
+ * One color per source of money, carried through a row's icon, edge, figures
+ * and links: federal and national programs blue, the school itself amber (the
+ * row not to skip), the state green, scholarships purple.
+ */
+// Line icons in the module's own stroke style, drawn in the row's color.
+const svg = (children: ReactNode) => (
+
+)
+const ICONS = {
+ // Columned building: federal and national programs.
+ big: svg(<>>),
+ // Mortarboard: the school's own aid.
+ uni: svg(<>>),
+ // Map pin: the student's state.
+ state: svg(<>>),
+ // Rosette: scholarships.
+ types: svg(<>>),
+}
+
+const ROWS = {
+ big: { color: '#1D7FC4', icon: ICONS.big },
+ uni: { color: '#C47A12', icon: ICONS.uni },
+ state: { color: MC, icon: ICONS.state },
+ types: { color: '#7048C8', icon: ICONS.types },
+} as const
+
+/** Each kind of scholarship gets its own chip, so the five read apart at a glance. */
+const CATEGORY_COLOR: Record = {
+ merit: '#7048C8',
+ need: '#1D7FC4',
+ institutional: '#C47A12',
+ national: MC,
+ specialized: '#3F5BA9',
+}
+
+const SANS = "'Outfit',sans-serif"
+
+export type AidGuideDestination = 'fafsa' | 'deadlines' | 'aid-compare' | 'scholarship-search'
+
+const Chevron = () => (
+
+)
+
+const ExtLink = ({ href, children, color = MC }: { href: string; children: ReactNode; color?: string }) => (
+
+ {children} ↗
+
+)
+
+/** One entry inside an open row: name and figure on top, the explanation under it. */
+const Item = ({ title, figure, children, links, color = MC, chip }: {
+ title: string
+ figure?: string
+ children: ReactNode
+ links?: ReactNode
+ color?: string
+ /** Render the title as a colored chip instead of bold text. */
+ chip?: boolean
+}) => (
+
+)
+
+const ProgramItem = ({ p, color }: { p: AidProgram; color: string }) => (
+ {l.label}) : Site}
+ >
+ {p.summary}{p.note && <> {p.note}>}
+
+)
+
+const GuaranteeItem = ({ g }: { g: AidGuarantee }) => (
+ Aid page}>
+ {g.detail} To get it: {g.action}
+
+)
+
+/** "Edvifi can ___" — one line at the foot of a row, pointing at the tool that does it. */
+const EdvifiCan = ({ can, cta, onClick, color = MC }: { can: string; cta: string; onClick: () => void; color?: string }) => (
+ // A quiet tinted strip rather than a banner: it should read as the next step,
+ // not as an ad, but still be the first thing the eye lands on at the bottom.
+
+
+
+
+
+ Edvifi can {can}
+
+
+
+)
+
+/** A collapsible row in the same shape as the checklist sections below it. */
+const Row = ({ kind, title, summary, tag, open, onToggle, children }: {
+ kind: keyof typeof ROWS
+ title: string
+ summary: string
+ tag?: string
+ open: boolean
+ onToggle: () => void
+ children: ReactNode
+}) => {
+ const { color, icon } = ROWS[kind]
+ const [hover, setHover] = useState(false)
+ const edge = open || hover ? `${color}45` : C.border
+ return (
+ // Longhands only. Mixing the `border` shorthand with `borderLeft` lets React
+ // re-apply the shorthand on toggle and wipe the colored edge.
+
+)
+
+export type GuideRowId = 'big' | 'uni' | 'state' | 'types'
+
+interface Props {
+ /** The student's state, when their ZIP tells us. Puts their grant first. */
+ homeState: GrantState | null
+ /** Guarantees at schools the student has added, in their list order. */
+ yourSchools: AidGuarantee[]
+ /** The list lookup failed, so "none on your list" would be a guess. */
+ listFailed: boolean
+ /** Which row is open. Held by the caller so it survives opening an article and coming back. */
+ open: GuideRowId | null
+ onOpenChange: (row: GuideRowId | null) => void
+ onGoTo: (dest: AidGuideDestination) => void
+}
+
+export default function AidGuideSections({ homeState, yourSchools, listFailed, open, onOpenChange, onGoTo }: Props) {
+ // The full list is only needed once the row is opened.
+ const [all, setAll] = useState(null)
+ const toggle = (id: GuideRowId) => {
+ // Reopening after a failed load tries again.
+ if (id === 'uni' && open !== 'uni' && all === 'failed') setAll(null)
+ onOpenChange(open === id ? null : id)
+ }
+ useEffect(() => {
+ if (open !== 'uni' || all !== null) return
+ let cancelled = false
+ fetchAllGuarantees()
+ .then((list) => { if (!cancelled) setAll(list) })
+ .catch(() => { if (!cancelled) setAll('failed') })
+ return () => { cancelled = true }
+ }, [open, all])
+
+ const homeGrant = STATE_GRANTS.find((g) => g.state === homeState)
+ const stateGrants = homeGrant ? [homeGrant, ...STATE_GRANTS.filter((g) => g !== homeGrant)] : STATE_GRANTS
+ const n = yourSchools.length
+ const checked = all && all !== 'failed' && all.checkedOn ? parseIsoDay(all.checkedOn) : null
+
+ return (
+
+ Know your aid
+
+ toggle('big')}>
+ {MAJOR_PROGRAMS.map((p) => )}
+ onGoTo('fafsa')} />
+
+
+ 0
+ ? `${n} ${n === 1 ? 'school' : 'schools'} on your list ${n === 1 ? 'has an aid guarantee' : 'have aid guarantees'}. Check whether you qualify`
+ : 'Many schools guarantee free tuition below a family income, if you file their forms'}
+ tag="Don’t skip"
+ open={open === 'uni'}
+ onToggle={() => toggle('uni')}
+ >
+
+ Guarantees only apply if you finish that school’s aid steps on time. That can mean the CSS Profile, the
+ school’s own form, or the FAFSA by an early date. Check the aid page of every school on your list.
+
+ {yourSchools.map((g) => )}
+
+
+ {n > 0 ? 'All' : 'See all'} {all && all !== 'failed' ? `${all.guarantees.length} ` : ''}schools with a guarantee
+
+ {all === null && Loading…}
+ {all === 'failed' && Couldn’t load the full list just now.}
+ {all && all !== 'failed' && (
+ <>
+ {all.guarantees.map((g) => )}
+ {checked &&
Checked against each school’s site on {formatCollegeDate(checked)}.
}
+ >
+ )}
+
+ onGoTo('aid-compare')} />
+
+
+ toggle('state')}
+ >
+ Most states have aid for residents who stay in state. If yours isn’t here, search “[your state] higher education grant”.
+ {stateGrants.map((g) => )}
+ onGoTo('deadlines')} />
+
+
+ toggle('types')}>
+ {SCHOLARSHIP_CATEGORIES.map((c) => {c.description} {c.example}.)}
+ onGoTo('scholarship-search')} />
+
+
+
+ Amounts are for {AID_FACTS_AS_OF} and change every year. Confirm on the official site.
+
+
+ )
+}
diff --git a/web/src/components/CollegeDiscoverTab.test.tsx b/web/src/components/CollegeDiscoverTab.test.tsx
index 724f2e5..136b635 100644
--- a/web/src/components/CollegeDiscoverTab.test.tsx
+++ b/web/src/components/CollegeDiscoverTab.test.tsx
@@ -23,6 +23,7 @@ const H = vi.hoisted(() => {
legacy_slug: null, emoji: null, early_action: null, early_decision: null, regular_decision: null,
fafsa_priority: null, css_profile: null, aid_notification: null, meets_full_need: null,
no_loan_policy: null, curated_at: null,
+ aid_guarantee: null, aid_guarantee_detail: null, aid_guarantee_needs_css: null, aid_guarantee_residents: null, aid_guarantee_action: null, aid_guarantee_url: null, aid_guarantee_checked_on: null,
application_fee_cents: null, fee_waiver_policy: null, fees_verified_at: null,
...over,
})
diff --git a/web/src/components/Dashboard.tsx b/web/src/components/Dashboard.tsx
index bf4f583..4a9987c 100644
--- a/web/src/components/Dashboard.tsx
+++ b/web/src/components/Dashboard.tsx
@@ -17,6 +17,7 @@ import { reportError } from '../lib/errorTracking'
import { resolveDeadlinePreferences } from '../lib/preferences'
import WeekOverview from './WeekOverview'
import DeadlinePanel from './DeadlinePanel'
+import OverviewRail, { RailToggle } from './OverviewRail'
import {
nextDueForModule,
type DeadlineEvent,
@@ -270,6 +271,14 @@ export default function Dashboard({ startIdx, answers, firstName, onSignOut }: P
onOpenDay={(day) => { setOpenModule(null); setCalendarDay(day); setPage('calendar') }}
/>
)
+
+ // The same rail inside each module's Overview, sharing this page's open state.
+ const moduleRail = (
+ setSidebarOpen((o) => !o)}>
+ {deadlineRail}
+
+ )
+
const nextDueByModule = useMemo(() => {
// A module card's "next due": not something already ticked off, and not a
// date the student put on one of its tasks (those are steps toward a
@@ -577,19 +586,11 @@ export default function Dashboard({ startIdx, answers, firstName, onSignOut }: P
{/* Sidebar toggle — fixed on the border */}
-
+ />
{/* Right sidebar — collapsible */}