Initial commit: Basic YSWS programs list website

This commit is contained in:
PawiX25 2024-12-10 00:24:40 +01:00
commit eda4dbf7bf
3 changed files with 995 additions and 0 deletions

19
index.html Normal file
View file

@ -0,0 +1,19 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Hack Club YSWS Programs</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<div class="container">
<h1 class="ultratitle">YSWS Programs</h1>
<p class="lead">A comprehensive list of Hack Club's "You Ship, We Ship" programs.</p>
<div id="programs-container">
</div>
</div>
<script src="script.js"></script>
</body>
</html>

322
script.js Normal file
View file

@ -0,0 +1,322 @@
const programs = {
indefinite: [
{
name: "Sprig",
description: "Build a JS game and play it on your own console.",
website: "https://sprig.hackclub.com/",
slack: "https://slack.com/archives/C02UN35M7LG",
slackChannel: "#sprig",
status: "active"
},
{
name: "Blot",
description: "Write code, make art, and get a drawing machine.",
website: "https://blot.hackclub.com/",
slack: "https://slack.com/archives/C04GCH8A91D",
slackChannel: "#blot",
status: "ended"
},
{
name: "OnBoard",
description: "Design a PCB and receive a $100 grant.",
website: "https://hackclub.com/onboard",
slack: "https://slack.com/archives/C056AMWSFKJ",
slackChannel: "#electronics",
status: "active"
},
{
name: "OnBoard Live",
description: "Design a PCB live on YouTube for $5/hour.",
website: null,
slack: "https://slack.com/archives/C07F3EA2L8G",
slackChannel: "#onboard-live",
status: "active"
},
{
name: "Boba Drops",
description: "Build a website and get boba!",
website: "https://boba.hackclub.com/",
slack: "https://slack.com/archives/C06UJR8QW0M",
slackChannel: "#boba",
status: "active"
},
{
name: "Hackaccino",
description: "Build a 3D website and get a free frappuccino.",
website: "https://fraps.hackclub.com/",
slack: "https://slack.com/archives/C078DFVL5LZ",
slackChannel: "#fraps",
status: "active"
},
{
name: "Cider",
description: "Create an iOS app and receive a $100 Apple Developer account to publish it.",
website: "https://cider.hackclub.com/",
slack: "https://slack.com/archives/C073DTGENJ2",
slackChannel: "#cider",
status: "active"
},
{
name: "Anchor",
description: "Design a VTuber-style logo for your High Seas project and receive custom stickers.",
website: "https://anchor.hackclub.com/",
slack: "https://slack.com/archives/C07V5401VMY",
slackChannel: "#anchor",
status: "active"
}
],
limitedTime: [
{
name: "Asylum",
description: "Fast-paced hardware YSWS challenges.",
website: null,
slack: "https://slack.com/archives/C083CCAAHM1",
slackChannel: "#asylum",
status: "active",
deadline: "Ends tomorrow"
},
{
name: "Pyramid Scheme",
description: "Put up Hack Club posters to earn prizes.",
website: null,
slack: "https://slack.com/archives/C07N1TCHY3T",
slackChannel: "#pyramid-scheme",
status: "active",
deadline: "Ends tomorrow"
},
{
name: "HackCraft",
description: "Create a Minecraft mod, and Hack Club sends you Minecraft Java! Ends January 31st, 2025.",
website: null,
slack: "https://slack.com/archives/C07NQ5QAYNQ",
slackChannel: "#mc-modding",
status: "active",
deadline: "Ends January 31st, 2025"
},
{
name: "Cascade",
description: "Create animations with CSS and receive art supplies.",
website: "https://cascade.hackclub.com/",
slack: "https://slack.com/archives/C07QA8HD48N",
slackChannel: "#cascade-ysws",
status: "active",
deadline: "Ends Thursday"
},
{
name: "High Seas",
description: "Work on projects, earn doubloons, and compete in the Wonderdome. Winners get extra doubloons; losers still earn some.",
website: "https://highseas.hackclub.com/",
slack: "https://slack.com/archives/C07PZMBUNDS",
slackChannel: "#high-seas",
status: "active",
deadline: "Ends January 31st, 2025"
},
{
name: "Riceathon",
description: "Customize your Linux install, and get programmer socks or a Blåhaj.",
website: "https://github.com/HackClub/riceathon",
slack: "https://slack.com/archives/C07MLF9A8H5",
slackChannel: "#riceathon",
status: "active",
deadline: "Ends January 10th, 2025"
}
],
upcoming: [
{
name: "Forge",
description: "Design a 3D model that solves a problem and receive a custom 3D printer.",
website: "https://forge.hackclub.com/",
slack: "https://slack.com/archives/C078GBDKC03",
slackChannel: "#forge-updates",
status: "upcoming"
},
{
name: "Vine YSWS",
description: "Create a song using open-source music software and receive a vinyl with your song.",
website: "https://vineysws.vercel.app/",
slack: "https://slack.com/archives/C07N0VA3YGJ",
slackChannel: "#vine-ysws",
status: "upcoming"
}
],
additional: [
{
name: "Google Dev YSWS",
description: "Make an Android app and earn credits for a Google Developer account.",
website: null,
slack: "https://slack.com/archives/C07N06B1FDY",
slackChannel: "#google-dev-ysws",
status: "active"
},
{
name: "Hack Store",
description: "Use a free alternative app store and get a Google Developer account.",
website: null,
slack: "https://slack.com/archives/C07BGFG6CDQ",
slackChannel: "#hack-store",
status: "active"
},
{
name: "Docs",
description: "Submit awesome documents, and Hack Club will print them into a book.",
website: null,
slack: "https://slack.com/archives/C07R7P3TT7W",
slackChannel: "#docs-ysws",
status: "active"
},
{
name: "Draw Sticker Get Sticker",
description: "Draw a sticker, and Hack Club will print and mail it to you.",
website: null,
slack: "https://slack.com/archives/C07Q862TYLQ",
slackChannel: "#draw-sticker-get-sticker",
status: "active"
},
{
name: "Light Up",
description: "Design an electronic circuit with lights, and Hack Club sends you the components and gifts.",
website: null,
slack: "https://slack.com/archives/C07RNEJ13LJ",
slackChannel: "#lightup-ysws",
status: "active"
},
{
name: "Aether YSWS",
description: "Build a Windows app, and Hack Club provides a Microsoft Store developer account.",
website: null,
slack: "https://slack.com/archives/C07V78URSGL",
slackChannel: "#aether-ysws",
status: "active"
},
{
name: "Onward",
description: "Build a robot using Arduino and receive one.",
website: null,
slack: "https://slack.com/archives/C079G5MKC93",
slackChannel: "#onward",
status: "active"
},
{
name: "Hack RTL",
description: "Create a desktop app using RTL-SDR, and Hack Club sends you a dongle.",
website: "https://hack-rtl.vercel.app/",
slack: "https://slack.com/archives/C082S5V95G8",
slackChannel: "#hack-rtl",
status: "active"
},
{
name: "Lab in a Box",
description: "Collaborate on projects in teams with resources provided by Hack Club.",
website: null,
slack: "https://slack.com/archives/C082G4HLZDK",
slackChannel: "#lab-in-a-box",
status: "active"
}
],
noYouShip: [
{
name: "Community Newsletter",
description: "Receive a fully handwritten monthly newsletter.",
website: null,
slack: "https://slack.com/archives/C07KS2794LX",
slackChannel: "#community-newsletter",
status: "active"
}
],
completed: [
{
name: "BrowserBuddy",
description: "Build a Chrome extension, and Hack Club provides $30 to launch it on Chrome Web Store.",
website: "https://browserbuddy.hackclub.com/",
slack: "https://slack.com/archives/C07MQBTNVRU",
slackChannel: "#browser-buddy",
status: "completed",
ended: "Ended November 20th"
},
{
name: "HAM Radio YSWS",
description: "Related to HAM radio projects.",
website: null,
slack: "https://slack.com/archives/C01G6UJT2RM",
slackChannel: "#hamradio",
status: "completed"
},
{
name: "Boba Manor",
description: "Website building with rewards.",
website: null,
slack: "https://slack.com/archives/C06UJR8QW0M",
slackChannel: "#boba",
status: "completed"
},
{
name: "LLM YSWS",
description: "Projects using language models.",
website: null,
slack: "https://slack.com/archives/C07KYNWR10W",
slackChannel: "#llm / #zrl-land",
status: "completed"
},
{
name: "The Bin",
description: "Hardware-related projects.",
website: "https://bin.hackclub.com/",
slack: "https://slack.com/archives/C01FXNNF6F2",
slackChannel: "#electronics",
status: "completed"
},
{
name: "Retrospect",
description: "Create a DOS game and have it delivered on a floppy disk.",
website: "https://retrospect.hackclub.com/",
slack: "https://slack.com/archives/C07MUFXNG82",
slackChannel: "#retrospect",
status: "completed",
ended: "Ended October 8th"
},
{
name: "Hackpad",
description: "Design a macropad and receive it.",
website: "https://github.com/hackclub/hackpad",
slack: "https://slack.com/archives/C07LESGH0B0",
slackChannel: "#hackpad",
status: "completed",
ended: "Ended October 21st"
}
]
};
function createProgramCard(program) {
return `
<div class="card program-card">
<div class="program-header">
<h3>${program.name}</h3>
<span class="program-status status-${program.status}">${program.status}</span>
</div>
<p>${program.description}</p>
${program.deadline ? `<div class="program-deadline">Ends: ${program.deadline}</div>` : ''}
<div class="program-links">
${program.website ? `<a href="${program.website}" target="_blank">Website</a>` : ''}
${program.slack ? `<a href="${program.slack}" target="_blank">${program.slackChannel}</a>` : ''}
</div>
</div>
`;
}
function renderPrograms() {
const container = document.getElementById('programs-container');
for (const [category, programsList] of Object.entries(programs)) {
const section = document.createElement('section');
section.className = 'category-section';
section.innerHTML = `
<h2 class="headline">${category.replace(/([A-Z])/g, ' $1').replace(/^./, str => str.toUpperCase())}</h2>
<div class="programs-grid">
${programsList.map(program => createProgramCard(program)).join('')}
</div>
`;
container.appendChild(section);
}
}
document.addEventListener('DOMContentLoaded', renderPrograms);

654
styles.css Normal file
View file

@ -0,0 +1,654 @@
:root {
--darker: #121217;
--dark: #17171d;
--darkless: #252429;
--black: #1f2d3d;
--steel: #273444;
--slate: #3c4858;
--muted: #8492a6;
--smoke: #e0e6ed;
--snow: #f9fafc;
--white: #ffffff;
--red: #ec3750;
--orange: #ff8c37;
--yellow: #f1c40f;
--green: #33d6a6;
--cyan: #5bc0de;
--blue: #338eda;
--purple: #a633d6;
--text: var(--black);
--background: var(--white);
--elevated: var(--white);
--sheet: var(--snow);
--sunken: var(--smoke);
--border: var(--smoke);
--primary: #ec3750;
--secondary: #8492a6;
--accent: #5bc0de;
--twitter: #1da1f2;
--facebook: #3b5998;
--instagram: #e1306c;
--breakpoint-xs: 32em;
--breakpoint-s: 48em;
--breakpoint-m: 64em;
--breakpoint-l: 96em;
--breakpoint-xl: 128em;
--spacing-0: 0px;
--spacing-1: 4px;
--spacing-2: 8px;
--spacing-3: 16px;
--spacing-4: 32px;
--spacing-5: 64px;
--spacing-6: 128px;
--spacing-7: 256px;
--spacing-8: 512px;
--font-1: 12px;
--font-2: 16px;
--font-3: 20px;
--font-4: 24px;
--font-5: 32px;
--font-6: 48px;
--font-7: 64px;
--font-8: 96px;
--font-9: 128px;
--font-10: 160px;
--font-11: 192px;
--line-height-limit: 0.875;
--line-height-title: 1;
--line-height-heading: 1.125;
--line-height-subheading: 1.25;
--line-height-caption: 1.375;
--line-height-body: 1.5;
--font-weight-body: 400;
--font-weight-bold: 700;
--font-weight-heading: var(--font-weight-bold);
--letter-spacing-title: -0.009em;
--letter-spacing-headline: 0.009em;
--size-wide-plus: 2048px;
--size-wide: 1536px;
--size-layout-plus: 1200px;
--size-layout: 1024px;
--size-copy-ultra: 980px;
--size-copy-plus: 768px;
--size-copy: 680px;
--size-narrow-plus: 600px;
--size-narrow: 512px;
--radii-small: 4px;
--radii-default: 8px;
--radii-extra: 12px;
--radii-ultra: 16px;
--radii-circle: 99999px;
--shadow-text: 0 1px 2px rgba(0, 0, 0, 0.25), 0 2px 4px rgba(0, 0, 0, 0.125);
--shadow-small: 0 1px 2px rgba(0, 0, 0, 0.0625),
0 2px 4px rgba(0, 0, 0, 0.0625);
--shadow-card: 0 4px 8px rgba(0, 0, 0, 0.125);
--shadow-elevated: 0 1px 2px rgba(0, 0, 0, 0.0625),
0 8px 12px rgba(0, 0, 0, 0.125);
}
body {
font-family: "Phantom Sans", system-ui, -apple-system, BlinkMacSystemFont,
"Segoe UI", Roboto, sans-serif;
line-height: var(--line-height-body);
font-weight: var(--font-weight-body);
margin: 0;
min-height: 100vh;
text-rendering: optimizeLegibility;
font-smooth: antialiased;
-moz-osx-font-smoothing: grayscale;
-webkit-font-smoothing: antialiased;
color: var(--text);
box-sizing: border-box;
}
* {
box-sizing: border-box;
}
.monospace {
font-family: "SF Mono", "Roboto Mono", Menlo, Consolas, monospace;
}
.heading {
font-weight: var(--font-weight-bold);
line-height: var(--line-height-heading);
margin-top: 0;
margin-bottom: 0;
}
.ultratitle {
font-weight: var(--font-weight-bold);
line-height: var(--line-height-limit);
letter-spacing: var(--letter-spacing-title);
}
.title {
font-weight: var(--font-weight-bold);
line-height: var(--line-height-title);
letter-spacing: var(--letter-spacing-title);
}
.subtitle {
margin-top: var(--spacing-3);
font-weight: var(--font-weight-body);
line-height: var(--line-height-subheading);
letter-spacing: var(--letter-spacing-headline);
}
.headline {
margin-top: var(--spacing-3);
margin-bottom: var(--spacing-3);
font-size: var(--font-4);
line-height: var(--line-height-heading);
letter-spacing: var(--letter-spacing-headline);
}
.subheadline {
margin-top: var(--spacing-0);
margin-bottom: var(--spacing-3);
font-size: var(--font-2);
line-height: var(--line-height-heading);
letter-spacing: var(--letter-spacing-headline);
}
.eyebrow {
color: var(--muted);
font-weight: var(--font-weight-heading);
letter-spacing: var(--letter-spacing-headline);
line-height: var(--line-height-subheading);
text-transform: uppercase;
margin-top: var(--spacing-0);
margin-bottom: var(--spacing-2);
}
.lead {
font-weight: var(--font-weight-body);
}
.caption {
color: var(--muted);
font-weight: var(--font-weight-body);
letter-spacing: var(--letter-spacing-headline);
line-height: var(--line-height-caption);
}
.pill {
border-radius: var(--radii-circle);
padding-left: var(--spacing-3);
padding-right: var(--spacing-3);
padding-top: var(--spacing-1);
padding-bottom: var(--spacing-1);
font-size: var(--font-2);
background: var(--primary);
color: var(--background);
font-weight: var(--font-weight-bold);
}
.outline-badge {
border-radius: var(--radii-circle);
padding-left: var(--spacing-3);
padding-right: var(--spacing-3);
padding-top: var(--spacing-1);
padding-bottom: var(--spacing-1);
font-size: var(--font-2);
background: none;
color: var(--muted);
border: 1px solid currentcolor;
font-weight: var(--font-weight-body);
}
button {
cursor: pointer;
font-family: inherit;
font-weight: var(--font-weight-bold);
border-radius: var(--radii-circle);
display: inline-flex;
align-items: center;
justify-content: center;
box-shadow: var(--shadow-card);
letter-spacing: var(--letter-spacing-headline);
-webkit-tap-highlight-color: transparent;
transition: transform 0.125s ease-in-out, box-shadow 0.125s ease-in-out;
box-sizing: border-box;
margin: 0;
min-width: 0;
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
text-align: center;
line-height: inherit;
-webkit-text-decoration: none;
text-decoration: none;
padding-left: 16px;
padding-right: 16px;
padding-top: 8px;
padding-bottom: 8px;
color: var(--theme-ui-colors-white, #ffffff);
background-color: var(--theme-ui-colors-primary, #ec3750);
border: 0;
font-size: var(--font-2);
}
button:focus,
button:hover {
box-shadow: var(--shadow-elevated);
transform: scale(1.0625);
}
button.lg {
font-size: var(--font-3)!important;
line-height: var(--line-height-title);
padding-left: var(--spacing-4);
padding-right: var(--spacing-4);
padding-top: var(--spacing-3);
padding-bottom: var(--spacing-3);
}
button.outline {
background: none;
color: var(--primary);
border: 2px solid currentcolor;
}
button.cta {
font-size: var(--font-2);
background-image: radial-gradient(
ellipse farthest-corner at top left,
var(--orange),
var(--red)
);
}
.card {
background: var(--elevated);
color: var(--text);
border-radius: var(--radii-extra);
box-shadow: var(--shadow-card);
overflow: hidden;
}
.card.sunken {
background: var(--sunken);
box-shadow: none;
}
.card.interactive {
text-decoration: none;
-webkit-tap-highlight-color: transparent;
transition: transform 0.125s ease-in-out, box-shadow 0.125s ease-in-out;
}
.card.interactive:hover,
.card.interactive:focus {
transform: scale(1.0625);
box-shadow: var(--shadow-elevated);
}
input,
textarea,
select {
background: var(--elevated);
color: var(--text);
font-family: inherit;
border-radius: var(--radii-small);
border: 0;
font-size: inherit;
padding: var(--spacing-2);
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
}
input::-webkit-input-placeholder,
input::-moz-placeholder,
input:-ms-input-placeholder,
textarea::-webkit-input-placeholder,
textarea::-moz-placeholder,
textarea:-ms-input-placeholder,
select::-webkit-input-placeholder,
select::-moz-placeholder,
select:-ms-input-placeholder {
color: var(--muted);
}
input[type="search"]::-webkit-search-decoration,
textarea[type="search"]::-webkit-search-decoration,
select[type="search"]::-webkit-search-decoration {
display: none;
}
input[type="checkbox"] {
-webkit-appearance: checkbox;
-moz-appearance: checkbox;
appearance: checkbox;
}
label {
color: var(--text);
display: flex;
flex-direction: column;
text-align: left;
line-height: var(--line-height-caption);
font-size: var(--font-3);
}
label.horizontal {
display: flex;
}
.slider {
color: var(--primary);
}
.form-hidden {
position: absolute;
height: 1px;
width: 1px;
clip: rect(1px, 1px, 1px, 1px);
white-space: nowrap;
}
.container {
width: 100%;
margin: auto;
padding-left: var(--spacing-3);
padding-right: var(--spacing-3);
}
h1 {
font-size: var(--font-5);
font-weight: var(--font-weight-bold);
line-height: var(--line-height-heading);
margin-top: 0;
margin-bottom: 0;
}
h2 {
font-size: var(--font-4);
font-weight: var(--font-weight-bold);
line-height: var(--line-height-heading);
margin-top: 0;
margin-bottom: 0;
}
h3 {
font-size: var(--font-3);
font-weight: var(--font-weight-bold);
line-height: var(--line-height-heading);
margin-top: 0;
margin-bottom: 0;
}
h4 {
font-size: var(--font-2);
font-weight: var(--font-weight-bold);
line-height: var(--line-height-heading);
margin-top: 0;
margin-bottom: 0;
}
h5 {
font-size: var(--font-1);
font-weight: var(--font-weight-bold);
line-height: var(--line-height-heading);
margin-top: 0;
margin-bottom: 0;
}
h6 {
font-weight: var(--font-weight-bold);
line-height: var(--line-height-heading);
margin-top: 0;
margin-bottom: 0;
}
p {
color: var(--text);
font-weight: var(--font-weight-body);
line-height: var(--line-height-body);
margin-top: var(--spacing-3);
margin-bottom: var(--spacing-3);
}
img {
max-width: 100%;
}
hr {
border: 0;
border-bottom: 1px solid var(--border);
}
a {
color: var(--primary);
text-decoration: underline;
text-underline-position: under;
}
a:focus,
a:hover {
text-decoration-style: wavy;
text-decoration-skip-ink: none;
}
pre {
font-family: "SF Mono", "Roboto Mono", Menlo, Consolas, monospace;
font-size: var(--font-1);
padding: var(--spacing-3);
color: var(--text);
background: var(--sunken);
overflow: auto;
border-radius: var(--radii-default);
white-space: inherit;
}
pre > code {
color: inherit;
margin-left: 0;
margin-right: 0;
padding-left: 0;
padding-right: 0;
}
code {
font-family: "SF Mono", "Roboto Mono", Menlo, Consolas, monospace;
font-size: inherit;
color: var(--purple);
background: var(--sunken);
overflow: auto;
border-radius: var(--radii-small);
margin-left: var(--spacing-1);
margin-right: var(--spacing-1);
padding-left: var(--spacing-1);
padding-right: var(--spacing-1);
}
p > code,
li > code {
color: var(--blue);
font-size: 0.875em;
}
p > a > code,
li > a > code {
color: var(--blue);
font-size: 0.875em;
}
li {
margin-top: var(--spacing-2);
margin-bottom: var(--spacing-2);
}
table {
width: 100%;
margin-top: var(--spacing-4);
margin-bottom: var(--spacing-4);
border-collapse: separate;
border-spacing: 0;
}
table > th,
table > td {
text-align: left;
padding: 4px;
padding-left: 0px;
border-color: var(--border);
border-bottom-style: solid;
}
th {
vertical-align: bottom;
border-bottom-width: 2px;
}
td {
vertical-align: top;
border-bottom-width: 1px;
}
.program-card {
margin-bottom: var(--spacing-3);
padding: var(--spacing-3);
height: 100%;
display: flex;
flex-direction: column;
}
.program-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: var(--spacing-2);
}
.program-status {
font-size: var(--font-1);
padding: var(--spacing-1) var(--spacing-2);
border-radius: var(--radii-small);
}
.status-active {
background-color: var(--green);
color: var(--white);
}
.status-completed {
background-color: var(--muted);
color: var(--white);
}
.status-upcoming {
background-color: var(--blue);
color: var(--white);
}
.program-links {
margin-top: var(--spacing-2);
display: flex;
gap: var(--spacing-2);
margin-top: auto;
padding-top: var(--spacing-3);
}
.category-section {
margin-bottom: var(--spacing-4);
}
.program-deadline {
font-size: var(--font-1);
color: var(--muted);
margin-top: var(--spacing-1);
}
.programs-grid {
display: grid;
grid-template-columns: 1fr;
gap: var(--spacing-3);
margin-top: var(--spacing-3);
}
@media screen and (min-width: 32em) {
.ultratitle {
font-size: var(--font-5);
}
.title {
font-size: var(--font-4);
}
.subtitle {
font-size: var(--font-2);
}
.eyebrow {
font-size: var(--font-3);
}
.lead {
font-size: var(--font-2);
margin-top: var(--spacing-2);
margin-bottom: var(--spacing-2);
}
.card {
padding: var(--spacing-3);
}
.container {
max-width: var(--size-layout);
}
.container.copy {
max-width: var(--size-copy);
}
.container.narrow {
max-width: var(--size-narrow);
}
.programs-grid {
grid-template-columns: repeat(2, 1fr);
}
}
@media screen and (min-width: 48em) {
.ultratitle {
font-size: var(--font-6);
}
.title {
font-size: var(--font-5);
}
.subtitle {
font-size: var(--font-3);
}
.eyebrow {
font-size: var(--font-4);
}
.lead {
font-size: var(--font-3);
margin-top: var(--spacing-3);
margin-bottom: var(--spacing-3);
}
.card {
padding: var(--spacing-4);
}
.programs-grid {
grid-template-columns: repeat(3, 1fr);
}
}
@media screen and (min-width: 64em) {
.ultratitle {
font-size: var(--font-7);
}
.title {
font-size: var(--font-6);
}
.container {
max-width: var(--size-layout-plus);
}
.container.wide {
max-width: var(--size-wide);
}
.container.copy {
max-width: var(--size-copy-plus);
}
.container.narrow {
max-width: var(--size-narrow-plus);
}
.programs-grid {
grid-template-columns: repeat(4, 1fr);
}
}