first pass - kryz inspired
This commit is contained in:
@@ -0,0 +1,65 @@
|
||||
<section class="about">
|
||||
<div class="container">
|
||||
<div class="about-intro">
|
||||
<img src="assets/svg/orange-flower.svg" alt="" class="about-flower-decor" aria-hidden="true">
|
||||
<h2>About <span class="text-accent">KMountain Flower</span></h2>
|
||||
<p class="section-intro">
|
||||
For nearly four decades, KMountain Flower has been the voice of our
|
||||
community — a nonprofit, listener-supported radio station dedicated to
|
||||
music, local news, and the stories that bind mountain towns together.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="about-grid">
|
||||
<div class="about-card">
|
||||
<div class="card-icon">🎵</div>
|
||||
<h3>Our Music</h3>
|
||||
<p>
|
||||
From bluegrass and folk to jazz and classical, our playlists reflect
|
||||
the rich cultural tapestry of the high country and its neighbors. We
|
||||
feature local artists alongside the world's best voices.
|
||||
</p>
|
||||
</div>
|
||||
<div class="about-card">
|
||||
<div class="card-icon">🤝</div>
|
||||
<h3>Our Community</h3>
|
||||
<p>
|
||||
Every show is staffed by volunteers who live and work in these
|
||||
mountains. From high school DJs to retired teachers, our team is your
|
||||
community — passionate about sharing what they love.
|
||||
</p>
|
||||
</div>
|
||||
<div class="about-card">
|
||||
<div class="card-icon">📡</div>
|
||||
<h3>Our Reach</h3>
|
||||
<p>
|
||||
Over the air on 98.7 FM and streaming live worldwide. Whether you're
|
||||
hiking the ridgeline or on the other side of the planet, our signal
|
||||
— and our welcome — goes everywhere.
|
||||
</p>
|
||||
</div>
|
||||
<div class="about-card">
|
||||
<div class="card-icon">🌱</div>
|
||||
<h3>Our Mission</h3>
|
||||
<p>
|
||||
To keep public radio free, independent, and deeply rooted in place.
|
||||
No corporate advertising, no spin — just music, conversation, and
|
||||
community served with care.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="about-cta">
|
||||
<div class="about-flower-divider" aria-hidden="true">
|
||||
<img src="assets/svg/small-flower.svg" alt="">
|
||||
</div>
|
||||
<h3>Become a Member</h3>
|
||||
<p class="section-intro">
|
||||
As a 501(c)(3) nonprofit, every donation keeps our airwaves free and our
|
||||
signal strong. Members receive exclusive perks and the satisfaction of
|
||||
knowing they helped make this possible.
|
||||
</p>
|
||||
<a routerLink="/donate" class="btn">Join the Station</a>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
@@ -0,0 +1,87 @@
|
||||
@use '../../styles/variables' as *;
|
||||
@use '../../styles/mixins' as *;
|
||||
|
||||
.about {
|
||||
padding: $spacing-3xl 0;
|
||||
background: var(--color-cream);
|
||||
}
|
||||
|
||||
.about-intro {
|
||||
text-align: center;
|
||||
margin-bottom: $spacing-2xl;
|
||||
|
||||
.about-flower-decor {
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
margin: 0 auto $spacing-md;
|
||||
opacity: 0.6;
|
||||
animation: float 5s ease-in-out infinite;
|
||||
}
|
||||
}
|
||||
|
||||
.about-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
|
||||
gap: $spacing-lg;
|
||||
margin-bottom: $spacing-3xl;
|
||||
}
|
||||
|
||||
.about-card {
|
||||
@include card-style;
|
||||
padding: $spacing-xl;
|
||||
text-align: center;
|
||||
background: var(--color-white);
|
||||
|
||||
.card-icon {
|
||||
font-size: 2.5rem;
|
||||
margin-bottom: $spacing-md;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: 1.3rem;
|
||||
margin-bottom: $spacing-sm;
|
||||
color: var(--color-primary);
|
||||
}
|
||||
|
||||
p {
|
||||
font-size: 0.95rem;
|
||||
color: var(--color-dark);
|
||||
line-height: 1.7;
|
||||
}
|
||||
}
|
||||
|
||||
.about-cta {
|
||||
text-align: center;
|
||||
padding: $spacing-2xl $spacing-lg;
|
||||
background: $mixed-gradient;
|
||||
border-radius: $radius-xl;
|
||||
color: var(--color-white);
|
||||
|
||||
.about-flower-divider {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
margin: 0 auto $spacing-md;
|
||||
|
||||
img {
|
||||
width: 100%;
|
||||
filter: brightness(1.2);
|
||||
}
|
||||
}
|
||||
|
||||
h3 {
|
||||
color: var(--color-white);
|
||||
font-size: 1.8rem;
|
||||
margin-bottom: $spacing-sm;
|
||||
}
|
||||
|
||||
.section-intro {
|
||||
color: rgba(255, 255, 255, 0.85);
|
||||
margin-bottom: $spacing-lg;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: #{$bp-md - 1px}) {
|
||||
.about-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
import { Component } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-about',
|
||||
standalone: true,
|
||||
imports: [],
|
||||
templateUrl: './about.component.html',
|
||||
styleUrl: './about.component.scss',
|
||||
})
|
||||
export class AboutComponent {}
|
||||
@@ -0,0 +1,8 @@
|
||||
import { ApplicationConfig, provideBrowserGlobalErrorListeners } from '@angular/core';
|
||||
import { provideRouter } from '@angular/router';
|
||||
|
||||
import { routes } from './app.routes';
|
||||
|
||||
export const appConfig: ApplicationConfig = {
|
||||
providers: [provideBrowserGlobalErrorListeners(), provideRouter(routes)],
|
||||
};
|
||||
@@ -0,0 +1,5 @@
|
||||
<app-navbar></app-navbar>
|
||||
<main>
|
||||
<router-outlet></router-outlet>
|
||||
</main>
|
||||
<app-footer></app-footer>
|
||||
@@ -0,0 +1,36 @@
|
||||
import { Routes } from '@angular/router';
|
||||
|
||||
export const routes: Routes = [
|
||||
{ path: '', redirectTo: '/', pathMatch: 'full' },
|
||||
{
|
||||
path: '',
|
||||
loadComponent: () =>
|
||||
import('./hero/hero.component').then((m) => m.HeroComponent),
|
||||
},
|
||||
{
|
||||
path: 'about',
|
||||
loadComponent: () =>
|
||||
import('./about/about.component').then((m) => m.AboutComponent),
|
||||
},
|
||||
{
|
||||
path: 'schedule',
|
||||
loadComponent: () =>
|
||||
import('./schedule/schedule.component').then((m) => m.ScheduleComponent),
|
||||
},
|
||||
{
|
||||
path: 'donate',
|
||||
loadComponent: () =>
|
||||
import('./donate/donate.component').then((m) => m.DonateComponent),
|
||||
},
|
||||
{
|
||||
path: 'events',
|
||||
loadComponent: () =>
|
||||
import('./events/events.component').then((m) => m.EventsComponent),
|
||||
},
|
||||
{
|
||||
path: 'contact',
|
||||
loadComponent: () =>
|
||||
import('./contact/contact.component').then((m) => m.ContactComponent),
|
||||
},
|
||||
{ path: '**', redirectTo: '' },
|
||||
];
|
||||
@@ -0,0 +1,13 @@
|
||||
@use '../styles/variables' as *;
|
||||
|
||||
app-navbar {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: 200;
|
||||
}
|
||||
|
||||
main {
|
||||
padding-top: 70px;
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { RouterOutlet } from '@angular/router';
|
||||
import { NavbarComponent } from './navbar/navbar.component';
|
||||
import { FooterComponent } from './footer/footer.component';
|
||||
|
||||
@Component({
|
||||
selector: 'app-root',
|
||||
standalone: true,
|
||||
imports: [RouterOutlet, NavbarComponent, FooterComponent],
|
||||
templateUrl: './app.html',
|
||||
styleUrl: './app.scss',
|
||||
})
|
||||
export class App {}
|
||||
@@ -0,0 +1,65 @@
|
||||
<section class="contact">
|
||||
<div class="container">
|
||||
<div class="contact-header">
|
||||
<img src="assets/svg/small-flower.svg" alt="" class="contact-flower" aria-hidden="true">
|
||||
<h2>Get in <span class="text-accent">Touch</span></h2>
|
||||
<p class="section-intro">
|
||||
Have a song request, want to volunteer, or just want to say hello?
|
||||
We'd love to hear from you.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="contact-grid">
|
||||
<!-- Contact form -->
|
||||
<div class="contact-form-wrapper">
|
||||
<form class="contact-form" (ngSubmit)="onSubmit()" #contactForm="ngForm">
|
||||
<div class="form-group">
|
||||
<label for="name">Your Name</label>
|
||||
<input id="name" type="text" ngModel name="name" required placeholder="Jane Doe">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="email">Email Address</label>
|
||||
<input id="email" type="email" ngModel name="email" required placeholder="jane@example.com">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="subject">Subject</label>
|
||||
<select id="subject" ngModel name="subject" required>
|
||||
<option value="" disabled selected>Choose a topic</option>
|
||||
<option value="general">General Inquiry</option>
|
||||
<option value="volunteer">Volunteer</option>
|
||||
<option value="donation">Donation Question</option>
|
||||
<option value="advertising">Community Announcement</option>
|
||||
<option value="song">Song Request</option>
|
||||
<option value="technical">Technical Support</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="message">Message</label>
|
||||
<textarea id="message" rows="5" ngModel name="message" required placeholder="Your message..."></textarea>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-form">Send Message</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<!-- Station info -->
|
||||
<div class="contact-info">
|
||||
<div class="info-card">
|
||||
<h4><span aria-hidden="true">📍</span> Studio Location</h4>
|
||||
<p>42 Pine Street<br>Mountain View, CO 80424</p>
|
||||
</div>
|
||||
<div class="info-card">
|
||||
<h4><span aria-hidden="true">📞</span> Phone</h4>
|
||||
<p>(970) 555-0198<br>Mon–Fri 8 AM – 6 MT</p>
|
||||
</div>
|
||||
<div class="info-card">
|
||||
<h4><span aria-hidden="true">✉️</span> Email</h4>
|
||||
<p><a href="mailto:hello@kmountainflower.org">hello@kmountainflower.org</a></p>
|
||||
</div>
|
||||
<div class="info-card">
|
||||
<h4><span aria-hidden="true">📡</span> Frequencies</h4>
|
||||
<p>98.7 FM — Mountain Region<br>Stream: kmountainflower.org/live</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
@@ -0,0 +1,135 @@
|
||||
@use '../../styles/variables' as *;
|
||||
@use '../../styles/mixins' as *;
|
||||
|
||||
.contact {
|
||||
padding: $spacing-3xl 0;
|
||||
background: var(--color-cream);
|
||||
}
|
||||
|
||||
.contact-header {
|
||||
text-align: center;
|
||||
margin-bottom: $spacing-2xl;
|
||||
|
||||
.contact-flower {
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
margin: 0 auto $spacing-md;
|
||||
opacity: 0.5;
|
||||
}
|
||||
}
|
||||
|
||||
.contact-grid {
|
||||
display: grid;
|
||||
grid-template-columns: 1.5fr 1fr;
|
||||
gap: $spacing-2xl;
|
||||
align-items: start;
|
||||
}
|
||||
|
||||
// Form
|
||||
.contact-form-wrapper {
|
||||
background: var(--color-white);
|
||||
padding: $spacing-xl;
|
||||
border-radius: $radius-lg;
|
||||
box-shadow: $shadow-md;
|
||||
}
|
||||
|
||||
.contact-form {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: $spacing-md;
|
||||
}
|
||||
|
||||
.form-group {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: $spacing-xs;
|
||||
|
||||
label {
|
||||
font-weight: 600;
|
||||
font-size: 0.9rem;
|
||||
color: var(--color-primary);
|
||||
}
|
||||
|
||||
input,
|
||||
select,
|
||||
textarea {
|
||||
padding: $spacing-sm;
|
||||
border: 1px solid var(--color-light);
|
||||
border-radius: $radius-sm;
|
||||
font-family: var(--font-primary);
|
||||
font-size: 0.95rem;
|
||||
color: var(--color-dark);
|
||||
background: var(--color-white);
|
||||
transition: border-color $transition-fast, box-shadow $transition-fast;
|
||||
|
||||
&:focus {
|
||||
outline: none;
|
||||
border-color: var(--color-accent);
|
||||
box-shadow: 0 0 0 3px rgba(232, 122, 46, 0.15);
|
||||
}
|
||||
|
||||
&::placeholder {
|
||||
color: var(--color-medium);
|
||||
}
|
||||
}
|
||||
|
||||
textarea {
|
||||
resize: vertical;
|
||||
min-height: 120px;
|
||||
}
|
||||
}
|
||||
|
||||
.btn-form {
|
||||
@include button-style($accent-orange, $neutral-white, $accent-orange-dark);
|
||||
align-self: flex-start;
|
||||
font-size: 1rem;
|
||||
padding: $spacing-sm $spacing-xl;
|
||||
}
|
||||
|
||||
// Info
|
||||
.contact-info {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: $spacing-md;
|
||||
}
|
||||
|
||||
.info-card {
|
||||
background: var(--color-white);
|
||||
padding: $spacing-lg;
|
||||
border-radius: $radius-md;
|
||||
box-shadow: $shadow-sm;
|
||||
|
||||
h4 {
|
||||
font-size: 1rem;
|
||||
color: var(--color-primary);
|
||||
margin-bottom: $spacing-sm;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: $spacing-xs;
|
||||
|
||||
span {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
}
|
||||
|
||||
p {
|
||||
font-size: 0.9rem;
|
||||
color: var(--color-dark);
|
||||
line-height: 1.6;
|
||||
|
||||
a {
|
||||
color: var(--color-accent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: #{$bp-md - 1px}) {
|
||||
.contact-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.btn-form {
|
||||
width: 100%;
|
||||
justify-content: center;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
|
||||
@Component({
|
||||
selector: 'app-contact',
|
||||
standalone: true,
|
||||
imports: [FormsModule],
|
||||
templateUrl: './contact.component.html',
|
||||
styleUrl: './contact.component.scss',
|
||||
})
|
||||
export class ContactComponent {
|
||||
onSubmit(): void {
|
||||
alert('Thank you for your message! We will get back to you shortly.');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
<section class="donate">
|
||||
<!-- Hero banner -->
|
||||
<div class="donate-banner">
|
||||
<div class="donate-banner-overlay">
|
||||
<div class="container donate-banner-content">
|
||||
<img src="assets/svg/orange-flower.svg" alt="" class="donate-flower-hero" aria-hidden="true">
|
||||
<h2>Keep the Music <span class="text-accent">Free</span></h2>
|
||||
<p class="donate-subtitle">
|
||||
KMountain Flower Radio is 100% listener-funded and independent.
|
||||
Your gift keeps our signal strong and our airwaves free for everyone.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="container">
|
||||
<!-- Donation tiers -->
|
||||
<div class="donate-tiers">
|
||||
<h3>Choose Your Level of Support</h3>
|
||||
<div class="tiers-grid">
|
||||
<div class="tier-card" *ngFor="let tier of tiers">
|
||||
<div class="tier-icon">{{ tier.icon }}</div>
|
||||
<div class="tier-amount">${{ tier.amount }}</div>
|
||||
<div class="tier-period">per month</div>
|
||||
<h4>{{ tier.name }}</h4>
|
||||
<ul class="tier-benefits">
|
||||
<li *ngFor="let benefit of tier.benefits">{{ benefit }}</li>
|
||||
</ul>
|
||||
<a href="#" class="btn btn-tier">Select {{ tier.name }}</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- One-time donation -->
|
||||
<div class="donate-one-time">
|
||||
<div class="donate-flower-divider" aria-hidden="true">
|
||||
<img src="assets/svg/small-flower.svg" alt="">
|
||||
</div>
|
||||
<h3>Or Make a One-Time Gift</h3>
|
||||
<p class="section-intro">
|
||||
Every dollar matters — from $5 to $5,000. No amount is too small to make
|
||||
a difference. All donations are tax-deductible (EIN: 84-XXXXXXX).
|
||||
</p>
|
||||
<a href="#" class="btn btn-lg">Give Any Amount</a>
|
||||
</div>
|
||||
|
||||
<!-- Why donate -->
|
||||
<div class="donate-why">
|
||||
<div class="why-grid">
|
||||
<div class="why-item">
|
||||
<span class="why-icon">📻</span>
|
||||
<strong>98.7 FM Signal</strong>
|
||||
<p>Covering 3 mountain counties and the valleys between</p>
|
||||
</div>
|
||||
<div class="why-item">
|
||||
<span class="why-icon">🎙️</span>
|
||||
<strong>24/7 On-Air</strong>
|
||||
<p>Over 15,000 hours of programming per year</p>
|
||||
</div>
|
||||
<div class="why-item">
|
||||
<span class="why-icon">🌍</span>
|
||||
<strong>Worldwide Stream</strong>
|
||||
<p>Accessible from every corner of the globe, free forever</p>
|
||||
</div>
|
||||
<div class="why-item">
|
||||
<span class="why-icon">🎓</span>
|
||||
<strong>Youth Programs</strong>
|
||||
<p>Free radio training for 200+ local students each year</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
@@ -0,0 +1,197 @@
|
||||
@use '../../styles/variables' as *;
|
||||
@use '../../styles/mixins' as *;
|
||||
|
||||
.donate {
|
||||
background: var(--color-cream);
|
||||
}
|
||||
|
||||
// Banner
|
||||
.donate-banner {
|
||||
position: relative;
|
||||
margin-bottom: $spacing-3xl;
|
||||
}
|
||||
|
||||
.donate-banner-overlay {
|
||||
background: $mixed-gradient;
|
||||
padding: $spacing-3xl $spacing-lg;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.donate-banner-content {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.donate-flower-hero {
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
margin: 0 auto $spacing-md;
|
||||
opacity: 0.7;
|
||||
animation: float 4s ease-in-out infinite;
|
||||
}
|
||||
|
||||
.donate-banner h2 {
|
||||
color: var(--color-white);
|
||||
font-size: 2.4rem;
|
||||
margin-bottom: $spacing-md;
|
||||
}
|
||||
|
||||
.donate-subtitle {
|
||||
color: rgba(255, 255, 255, 0.85);
|
||||
font-size: 1.1rem;
|
||||
max-width: 550px;
|
||||
margin: 0 auto;
|
||||
line-height: 1.7;
|
||||
}
|
||||
|
||||
// Tiers
|
||||
.donate-tiers {
|
||||
text-align: center;
|
||||
margin-bottom: $spacing-3xl;
|
||||
|
||||
h3 {
|
||||
font-size: 1.8rem;
|
||||
margin-bottom: $spacing-xl;
|
||||
}
|
||||
}
|
||||
|
||||
.tiers-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
|
||||
gap: $spacing-lg;
|
||||
margin-bottom: $spacing-xl;
|
||||
}
|
||||
|
||||
.tier-card {
|
||||
@include card-style;
|
||||
padding: $spacing-xl;
|
||||
text-align: center;
|
||||
background: var(--color-white);
|
||||
border-top: 4px solid var(--color-accent);
|
||||
|
||||
.tier-icon {
|
||||
font-size: 2rem;
|
||||
margin-bottom: $spacing-sm;
|
||||
}
|
||||
|
||||
.tier-amount {
|
||||
font-size: 2.8rem;
|
||||
font-weight: 700;
|
||||
color: var(--color-accent);
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.tier-period {
|
||||
font-size: 0.85rem;
|
||||
color: var(--color-medium);
|
||||
margin-bottom: $spacing-md;
|
||||
}
|
||||
|
||||
h4 {
|
||||
font-size: 1.2rem;
|
||||
color: var(--color-primary);
|
||||
margin-bottom: $spacing-md;
|
||||
}
|
||||
|
||||
.tier-benefits {
|
||||
list-style: none;
|
||||
text-align: left;
|
||||
margin-bottom: $spacing-lg;
|
||||
|
||||
li {
|
||||
padding: $spacing-xs 0;
|
||||
font-size: 0.9rem;
|
||||
color: var(--color-dark);
|
||||
border-bottom: 1px solid var(--color-light);
|
||||
|
||||
&::before {
|
||||
content: '✓ ';
|
||||
color: $success-green;
|
||||
font-weight: 700;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.btn-tier {
|
||||
@include button-style($accent-orange, $neutral-white, $accent-orange-dark);
|
||||
display: inline-block;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
||||
// One-time
|
||||
.donate-one-time {
|
||||
text-align: center;
|
||||
padding: $spacing-2xl $spacing-lg;
|
||||
background: var(--color-primary);
|
||||
border-radius: $radius-xl;
|
||||
margin-bottom: $spacing-3xl;
|
||||
|
||||
.donate-flower-divider {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
margin: 0 auto $spacing-md;
|
||||
|
||||
img {
|
||||
width: 100%;
|
||||
filter: brightness(1.2);
|
||||
}
|
||||
}
|
||||
|
||||
h3 {
|
||||
color: var(--color-white);
|
||||
font-size: 1.6rem;
|
||||
margin-bottom: $spacing-sm;
|
||||
}
|
||||
|
||||
.section-intro {
|
||||
color: rgba(255, 255, 255, 0.8);
|
||||
margin-bottom: $spacing-lg;
|
||||
}
|
||||
|
||||
.btn-lg {
|
||||
@include button-style($accent-orange, $neutral-white, $accent-orange-dark);
|
||||
font-size: 1.2rem;
|
||||
padding: $spacing-md $spacing-2xl;
|
||||
}
|
||||
}
|
||||
|
||||
// Why
|
||||
.donate-why {
|
||||
padding-bottom: $spacing-xl;
|
||||
}
|
||||
|
||||
.why-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
|
||||
gap: $spacing-lg;
|
||||
|
||||
.why-item {
|
||||
text-align: center;
|
||||
padding: $spacing-lg;
|
||||
|
||||
.why-icon {
|
||||
display: block;
|
||||
font-size: 2.5rem;
|
||||
margin-bottom: $spacing-sm;
|
||||
}
|
||||
|
||||
strong {
|
||||
display: block;
|
||||
color: var(--color-primary);
|
||||
margin-bottom: $spacing-xs;
|
||||
font-size: 1.05rem;
|
||||
}
|
||||
|
||||
p {
|
||||
font-size: 0.9rem;
|
||||
color: var(--color-medium);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: #{$bp-md - 1px}) {
|
||||
.donate-banner h2 { font-size: 1.8rem; }
|
||||
.tiers-grid { grid-template-columns: 1fr; max-width: 320px; margin-left: auto; margin-right: auto; }
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { NgFor } from '@angular/common';
|
||||
|
||||
interface Tier {
|
||||
name: string;
|
||||
amount: number;
|
||||
icon: string;
|
||||
benefits: string[];
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'app-donate',
|
||||
standalone: true,
|
||||
imports: [NgFor],
|
||||
templateUrl: './donate.component.html',
|
||||
styleUrl: './donate.component.scss',
|
||||
})
|
||||
export class DonateComponent {
|
||||
readonly tiers: Tier[] = [
|
||||
{
|
||||
name: 'Seed',
|
||||
amount: 5,
|
||||
icon: '🌱',
|
||||
benefits: [
|
||||
'Digital thank-you card',
|
||||
'Name listed on our website',
|
||||
'Quarterly newsletter',
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'Stream',
|
||||
amount: 15,
|
||||
icon: '🎵',
|
||||
benefits: [
|
||||
'All Seed benefits',
|
||||
'KMountain Flower pin',
|
||||
'Priority show-request line',
|
||||
'Annual station update call',
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'Ridge',
|
||||
amount: 30,
|
||||
icon: '🏔️',
|
||||
benefits: [
|
||||
'All Stream benefits',
|
||||
'Official member patch',
|
||||
'Exclusive show invitations',
|
||||
'Annual station tour',
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'Summit',
|
||||
amount: 60,
|
||||
icon: '⭐',
|
||||
benefits: [
|
||||
'All Ridge benefits',
|
||||
'Featured on the Summit Wall',
|
||||
'Name on-air during anniversary special',
|
||||
'Lifetime patron recognition',
|
||||
],
|
||||
},
|
||||
];
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
<section class="events">
|
||||
<div class="container">
|
||||
<div class="events-header">
|
||||
<img src="assets/svg/small-flower.svg" alt="" class="events-flower" aria-hidden="true">
|
||||
<h2>Upcoming <span class="text-accent">Events</span></h2>
|
||||
<p class="section-intro">
|
||||
Come meet the team, enjoy live music, and support public radio in
|
||||
person. All events are open to the community — friends and family of
|
||||
listeners welcome.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="events-list">
|
||||
<div class="event-card" *ngFor="let event of upcomingEvents">
|
||||
<div class="event-date">
|
||||
<span class="event-month">Jul</span>
|
||||
<span class="event-day">12</span>
|
||||
<span class="event-year">2026</span>
|
||||
</div>
|
||||
<div class="event-content">
|
||||
<h3>{{ event.title }}</h3>
|
||||
<p>{{ event.description }}</p>
|
||||
<div class="event-meta">
|
||||
<span class="event-location">
|
||||
<span aria-hidden="true">📍</span> {{ event.location }}
|
||||
</span>
|
||||
<a href="#" class="event-rsvp">Learn More →</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="event-icon" aria-hidden="true">{{ event.icon }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
@@ -0,0 +1,135 @@
|
||||
@use '../../styles/variables' as *;
|
||||
@use '../../styles/mixins' as *;
|
||||
|
||||
.events {
|
||||
padding: $spacing-3xl 0;
|
||||
background: var(--color-white);
|
||||
}
|
||||
|
||||
.events-header {
|
||||
text-align: center;
|
||||
margin-bottom: $spacing-2xl;
|
||||
|
||||
.events-flower {
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
margin: 0 auto $spacing-md;
|
||||
opacity: 0.5;
|
||||
}
|
||||
}
|
||||
|
||||
.events-list {
|
||||
max-width: 800px;
|
||||
margin: 0 auto;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: $spacing-lg;
|
||||
}
|
||||
|
||||
.event-card {
|
||||
@include card-style;
|
||||
display: flex;
|
||||
background: var(--color-white);
|
||||
overflow: hidden;
|
||||
|
||||
.event-date {
|
||||
flex-shrink: 0;
|
||||
background: $mixed-gradient;
|
||||
color: var(--color-white);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: $spacing-md $spacing-lg;
|
||||
min-width: 90px;
|
||||
text-align: center;
|
||||
|
||||
.event-month {
|
||||
font-size: 0.85rem;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.1em;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.event-day {
|
||||
font-size: 2.2rem;
|
||||
font-weight: 700;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.event-year {
|
||||
font-size: 0.75rem;
|
||||
opacity: 0.8;
|
||||
}
|
||||
}
|
||||
|
||||
.event-content {
|
||||
flex: 1;
|
||||
padding: $spacing-lg;
|
||||
|
||||
h3 {
|
||||
font-size: 1.3rem;
|
||||
color: var(--color-primary);
|
||||
margin-bottom: $spacing-sm;
|
||||
}
|
||||
|
||||
p {
|
||||
font-size: 0.95rem;
|
||||
color: var(--color-dark);
|
||||
line-height: 1.6;
|
||||
margin-bottom: $spacing-sm;
|
||||
}
|
||||
}
|
||||
|
||||
.event-meta {
|
||||
display: flex;
|
||||
gap: $spacing-md;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
font-size: 0.85rem;
|
||||
color: var(--color-medium);
|
||||
|
||||
.event-location {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.event-rsvp {
|
||||
color: var(--color-accent);
|
||||
font-weight: 600;
|
||||
transition: color $transition-fast;
|
||||
|
||||
&:hover {
|
||||
color: var(--color-accent-dark);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.event-icon {
|
||||
flex-shrink: 0;
|
||||
font-size: 3rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding-right: $spacing-md;
|
||||
opacity: 0.7;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: #{$bp-md - 1px}) {
|
||||
.event-card {
|
||||
flex-direction: column;
|
||||
|
||||
.event-date {
|
||||
flex-direction: row;
|
||||
gap: $spacing-sm;
|
||||
padding: $spacing-sm $spacing-md;
|
||||
}
|
||||
|
||||
.event-icon {
|
||||
padding-right: 0;
|
||||
padding-top: $spacing-sm;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { NgFor } from '@angular/common';
|
||||
|
||||
interface Event {
|
||||
date: string;
|
||||
title: string;
|
||||
description: string;
|
||||
location: string;
|
||||
icon: string;
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'app-events',
|
||||
standalone: true,
|
||||
imports: [NgFor],
|
||||
templateUrl: './events.component.html',
|
||||
styleUrl: './events.component.scss',
|
||||
})
|
||||
export class EventsComponent {
|
||||
readonly upcomingEvents: Event[] = [
|
||||
{
|
||||
date: 'July 12, 2026',
|
||||
title: 'Summer Sounds Festival',
|
||||
description: 'A full day of live local music, community booths, and station meet-and-greet at the foothills park. Free admission — donations welcome.',
|
||||
location: 'Foothills Community Park',
|
||||
icon: '🎵',
|
||||
},
|
||||
{
|
||||
date: 'August 5, 2026',
|
||||
title: 'Annual Fundraiser Gala',
|
||||
description: 'Our biggest fundraiser of the year! Enjoy dinner, silent auction, and performances from past guest artists.',
|
||||
location: 'Mountain View Ballroom',
|
||||
icon: '🎙️',
|
||||
},
|
||||
{
|
||||
date: 'September 18, 2026',
|
||||
title: 'Volunteer Open House',
|
||||
description: 'Tour the studio, meet the team, and learn how you can help keep our free stream alive. New volunteers always welcome!',
|
||||
location: 'KMTN Studio — 42 Pine St',
|
||||
icon: '🤝',
|
||||
},
|
||||
{
|
||||
date: 'October 30, 2026',
|
||||
title: 'Harvest Moon Broadcast',
|
||||
description: 'Special live broadcast from the harvest moon gathering. Featuring folk, bluegrass, and indigenous music.',
|
||||
location: 'Ridgefield Amphitheater',
|
||||
icon: '🌙',
|
||||
},
|
||||
];
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
<footer class="footer">
|
||||
<div class="container">
|
||||
<div class="footer-top">
|
||||
<div class="footer-brand">
|
||||
<img src="assets/svg/small-flower.svg" alt="" class="footer-flower" aria-hidden="true">
|
||||
<h3>
|
||||
<span class="brand-m">K</span>MOUNTAIN
|
||||
<span class="brand-a">FLOWER</span> Radio
|
||||
</h3>
|
||||
<p class="footer-tagline">
|
||||
Community-powered nonprofit public radio — free to stream, funded by you.
|
||||
</p>
|
||||
<p class="footer-legal">
|
||||
KMountain Flower Radio is a 501(c)(3) nonprofit organization.<br>
|
||||
EIN: 84-XXXXXXX. All donations are tax-deductible.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="footer-links">
|
||||
<div class="footer-col">
|
||||
<h4>Quick Links</h4>
|
||||
<ul>
|
||||
<li><a routerLink="/about">About Us</a></li>
|
||||
<li><a routerLink="/schedule">Schedule</a></li>
|
||||
<li><a routerLink="/events">Events</a></li>
|
||||
<li><a routerLink="/donate">Donate</a></li>
|
||||
<li><a routerLink="/contact">Contact</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="footer-col">
|
||||
<h4>Support</h4>
|
||||
<ul>
|
||||
<li><a routerLink="/donate">Become a Member</a></li>
|
||||
<li><a href="#">Volunteer</a></li>
|
||||
<li><a href="#">Corporate Giving</a></li>
|
||||
<li><a href="#">Planned Giving</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="footer-col">
|
||||
<h4>Follow Us</h4>
|
||||
<div class="social-links">
|
||||
<a href="#" aria-label="Facebook" class="social-link">📘</a>
|
||||
<a href="#" aria-label="Twitter" class="social-link">🐦</a>
|
||||
<a href="#" aria-label="Instagram" class="social-link">📷</a>
|
||||
<a href="#" aria-label="YouTube" class="social-link">📺</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="footer-bottom">
|
||||
<p>© 1987–2026 KMountain Flower Radio. All rights reserved.</p>
|
||||
<p class="footer-made">
|
||||
Made with 🧡 in the mountains
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
@@ -0,0 +1,132 @@
|
||||
@use '../../styles/variables' as *;
|
||||
@use '../../styles/mixins' as *;
|
||||
|
||||
.footer {
|
||||
background: var(--color-primary-dark);
|
||||
color: rgba(255, 255, 255, 0.8);
|
||||
padding: $spacing-3xl 0 $spacing-lg;
|
||||
}
|
||||
|
||||
.footer-top {
|
||||
display: grid;
|
||||
grid-template-columns: 1.2fr 2fr;
|
||||
gap: $spacing-2xl;
|
||||
padding-bottom: $spacing-2xl;
|
||||
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
|
||||
.footer-brand {
|
||||
.footer-flower {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
margin-bottom: $spacing-sm;
|
||||
filter: brightness(1.1);
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: 1.4rem;
|
||||
color: var(--color-white);
|
||||
margin-bottom: $spacing-sm;
|
||||
line-height: 1.2;
|
||||
|
||||
.brand-m {
|
||||
color: var(--color-white);
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.brand-a {
|
||||
@include gradient-text(var(--color-accent-light), var(--color-accent));
|
||||
}
|
||||
}
|
||||
|
||||
.footer-tagline {
|
||||
font-size: 0.95rem;
|
||||
line-height: 1.6;
|
||||
margin-bottom: $spacing-md;
|
||||
}
|
||||
|
||||
.footer-legal {
|
||||
font-size: 0.8rem;
|
||||
color: rgba(255, 255, 255, 0.5);
|
||||
line-height: 1.5;
|
||||
}
|
||||
}
|
||||
|
||||
.footer-links {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
gap: $spacing-xl;
|
||||
align-self: start;
|
||||
}
|
||||
|
||||
.footer-col {
|
||||
h4 {
|
||||
color: var(--color-accent-light);
|
||||
font-size: 1rem;
|
||||
margin-bottom: $spacing-md;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
ul {
|
||||
list-style: none;
|
||||
|
||||
li {
|
||||
margin-bottom: $spacing-xs;
|
||||
|
||||
a {
|
||||
color: rgba(255, 255, 255, 0.7);
|
||||
font-size: 0.9rem;
|
||||
transition: color $transition-fast;
|
||||
|
||||
&:hover {
|
||||
color: var(--color-accent-light);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.social-links {
|
||||
display: flex;
|
||||
gap: $spacing-sm;
|
||||
|
||||
.social-link {
|
||||
font-size: 1.5rem;
|
||||
text-decoration: none;
|
||||
transition: transform $transition-fast;
|
||||
|
||||
&:hover {
|
||||
transform: scale(1.15);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.footer-bottom {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding-top: $spacing-lg;
|
||||
font-size: 0.85rem;
|
||||
color: rgba(255, 255, 255, 0.5);
|
||||
|
||||
.footer-made {
|
||||
font-style: italic;
|
||||
color: rgba(255, 255, 255, 0.4);
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: #{$bp-md - 1px}) {
|
||||
.footer-top {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.footer-links {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.footer-bottom {
|
||||
flex-direction: column;
|
||||
gap: $spacing-sm;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
import { Component } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-footer',
|
||||
standalone: true,
|
||||
imports: [],
|
||||
templateUrl: './footer.component.html',
|
||||
styleUrl: './footer.component.scss',
|
||||
})
|
||||
export class FooterComponent {}
|
||||
@@ -0,0 +1,42 @@
|
||||
<section class="hero">
|
||||
<!-- Mountain background layer -->
|
||||
<div class="hero-mountains" aria-hidden="true">
|
||||
<img src="assets/svg/mountain-silhouette.svg" alt="">
|
||||
</div>
|
||||
|
||||
<!-- Gradient overlay -->
|
||||
<div class="hero-gradient"></div>
|
||||
|
||||
<!-- Content -->
|
||||
<div class="hero-content container">
|
||||
<div class="hero-inner">
|
||||
<div class="hero-icon">
|
||||
<img src="assets/svg/orange-flower.svg" alt="" class="hero-flower">
|
||||
</div>
|
||||
<h1 class="hero-title">
|
||||
<span class="hero-line1">KMountain</span>
|
||||
<span class="hero-line2 text-accent">Flower Radio</span>
|
||||
</h1>
|
||||
<p class="hero-subtitle">
|
||||
Your community-powered, nonprofit radio station — bringing music,
|
||||
stories, and connection to the mountain towns and beyond since 1987.
|
||||
</p>
|
||||
<p class="hero-subtitle hero-tagline">
|
||||
Free to stream. Funded by you. Always on-air.
|
||||
</p>
|
||||
<div class="hero-actions">
|
||||
<a routerLink="/donate" class="btn btn-hero-primary">Support the Station</a>
|
||||
<a routerLink="/schedule" class="btn btn-hero-secondary">View Schedule</a>
|
||||
</div>
|
||||
<div class="hero-listeners">
|
||||
<span class="listeners-dot"></span>
|
||||
<span class="listeners-text">Live on-air now — Stream free worldwide</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Mountain divider at bottom -->
|
||||
<div class="hero-divider" aria-hidden="true">
|
||||
<img src="assets/svg/mountain-divider.svg" alt="">
|
||||
</div>
|
||||
</section>
|
||||
@@ -0,0 +1,166 @@
|
||||
@use '../../styles/variables' as *;
|
||||
@use '../../styles/mixins' as *;
|
||||
|
||||
.hero {
|
||||
position: relative;
|
||||
min-height: 100vh;
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.hero-mountains {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
z-index: 0;
|
||||
|
||||
img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
object-position: center bottom;
|
||||
}
|
||||
}
|
||||
|
||||
.hero-gradient {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
z-index: 1;
|
||||
background: $sky-gradient;
|
||||
opacity: 0.85;
|
||||
}
|
||||
|
||||
.hero-content {
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
text-align: center;
|
||||
padding: $spacing-3xl $spacing-lg;
|
||||
}
|
||||
|
||||
.hero-inner {
|
||||
@include fade-in;
|
||||
}
|
||||
|
||||
.hero-icon {
|
||||
margin-bottom: $spacing-lg;
|
||||
animation: float 4s ease-in-out infinite;
|
||||
|
||||
.hero-flower {
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
margin: 0 auto;
|
||||
filter: drop-shadow(0 4px 12px rgba(232, 122, 46, 0.4));
|
||||
}
|
||||
}
|
||||
|
||||
.hero-title {
|
||||
margin-bottom: $spacing-md;
|
||||
}
|
||||
|
||||
.hero-line1 {
|
||||
display: block;
|
||||
font-size: 3.5rem;
|
||||
font-weight: 700;
|
||||
color: var(--color-white);
|
||||
letter-spacing: 0.05em;
|
||||
}
|
||||
|
||||
.hero-line2 {
|
||||
display: block;
|
||||
font-size: 3rem;
|
||||
font-weight: 700;
|
||||
@include gradient-text(var(--color-accent-light), var(--color-accent));
|
||||
}
|
||||
|
||||
.hero-subtitle {
|
||||
font-size: 1.15rem;
|
||||
color: rgba(255, 255, 255, 0.85);
|
||||
max-width: 600px;
|
||||
margin: 0 auto $spacing-sm;
|
||||
line-height: 1.7;
|
||||
}
|
||||
|
||||
.hero-tagline {
|
||||
font-style: italic;
|
||||
color: var(--color-accent-muted);
|
||||
font-size: 1.05rem;
|
||||
}
|
||||
|
||||
.hero-actions {
|
||||
display: flex;
|
||||
gap: $spacing-md;
|
||||
justify-content: center;
|
||||
flex-wrap: wrap;
|
||||
margin: $spacing-lg 0;
|
||||
}
|
||||
|
||||
.btn-hero-primary {
|
||||
@include button-style($accent-orange, $neutral-white, $accent-orange-dark);
|
||||
font-size: 1.1rem;
|
||||
padding: $spacing-sm $spacing-xl;
|
||||
letter-spacing: 0.03em;
|
||||
}
|
||||
|
||||
.btn-hero-secondary {
|
||||
@include button-style(transparent, var(--color-white), rgba(255,255,255,0.15));
|
||||
border: 2px solid rgba(255, 255, 255, 0.4);
|
||||
font-size: 1.1rem;
|
||||
padding: $spacing-sm $spacing-xl;
|
||||
letter-spacing: 0.03em;
|
||||
|
||||
&:hover {
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
border-color: rgba(255, 255, 255, 0.7);
|
||||
}
|
||||
}
|
||||
|
||||
.hero-listeners {
|
||||
margin-top: $spacing-xl;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: $spacing-sm;
|
||||
font-size: 0.95rem;
|
||||
color: rgba(255, 255, 255, 0.7);
|
||||
}
|
||||
|
||||
.listeners-dot {
|
||||
display: inline-block;
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
border-radius: $radius-full;
|
||||
background: $success-green;
|
||||
animation: pulse 2s ease-in-out infinite;
|
||||
}
|
||||
|
||||
@keyframes pulse {
|
||||
0%, 100% { opacity: 1; box-shadow: 0 0 0 0 rgba(74, 158, 79, 0.4); }
|
||||
50% { opacity: 0.7; box-shadow: 0 0 0 6px rgba(74, 158, 79, 0); }
|
||||
}
|
||||
|
||||
.hero-divider {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: 3;
|
||||
|
||||
img {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
// Responsive
|
||||
@media (max-width: #{$bp-md - 1px}) {
|
||||
.hero-line1 { font-size: 2.5rem; }
|
||||
.hero-line2 { font-size: 2.2rem; }
|
||||
.hero-subtitle { font-size: 1rem; }
|
||||
.hero-flower { width: 70px; height: 70px; }
|
||||
.hero-actions { flex-direction: column; align-items: center; }
|
||||
}
|
||||
|
||||
@media (max-width: #{$bp-sm - 1px}) {
|
||||
.hero-line1 { font-size: 2rem; }
|
||||
.hero-line2 { font-size: 1.8rem; }
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
import { Component } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-hero',
|
||||
standalone: true,
|
||||
imports: [],
|
||||
templateUrl: './hero.component.html',
|
||||
styleUrl: './hero.component.scss',
|
||||
})
|
||||
export class HeroComponent {}
|
||||
@@ -0,0 +1,28 @@
|
||||
<nav class="navbar" role="navigation" aria-label="Main navigation">
|
||||
<div class="container navbar-inner">
|
||||
<a routerLink="/" class="navbar-brand" routerLinkActive="active">
|
||||
<img src="assets/svg/small-flower.svg" alt="" class="brand-flower" aria-hidden="true">
|
||||
<span class="brand-name">
|
||||
<span class="brand-mountain">K</span>MOUNTAIN
|
||||
<span class="brand-accent">FLOWER</span>
|
||||
</span>
|
||||
<span class="brand-tagline">Community Radio — Est. 1987</span>
|
||||
</a>
|
||||
|
||||
<button class="navbar-toggle" aria-label="Toggle menu" (click)="toggleMenu()">
|
||||
<span class="bar"></span>
|
||||
<span class="bar"></span>
|
||||
<span class="bar"></span>
|
||||
</button>
|
||||
|
||||
<div class="navbar-menu" [class.open]="menuOpen">
|
||||
<ul class="nav-links">
|
||||
<li><a routerLink="/about" routerLinkActive="active" (click)="closeMenu()">About</a></li>
|
||||
<li><a routerLink="/schedule" routerLinkActive="active" (click)="closeMenu()">Schedule</a></li>
|
||||
<li><a routerLink="/events" routerLinkActive="active" (click)="closeMenu()">Events</a></li>
|
||||
<li><a routerLink="/contact" routerLinkActive="active" (click)="closeMenu()">Contact</a></li>
|
||||
</ul>
|
||||
<a routerLink="/donate" class="btn btn-donate-nav" (click)="closeMenu()">Donate Now</a>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
@@ -0,0 +1,143 @@
|
||||
@use '../../styles/variables' as *;
|
||||
@use '../../styles/mixins' as *;
|
||||
|
||||
.navbar {
|
||||
background: var(--color-primary-dark);
|
||||
padding: $spacing-sm 0;
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: $z-sticky;
|
||||
box-shadow: $shadow-md;
|
||||
}
|
||||
|
||||
.navbar-inner {
|
||||
@include flex-between;
|
||||
}
|
||||
|
||||
.navbar-brand {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: $spacing-sm;
|
||||
text-decoration: none;
|
||||
color: var(--color-white);
|
||||
}
|
||||
|
||||
.brand-flower {
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
}
|
||||
|
||||
.brand-name {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
line-height: 1.1;
|
||||
}
|
||||
|
||||
.brand-mountain {
|
||||
font-family: var(--font-heading);
|
||||
font-size: 1.4rem;
|
||||
font-weight: 700;
|
||||
color: var(--color-white);
|
||||
letter-spacing: 0.08em;
|
||||
}
|
||||
|
||||
.brand-accent {
|
||||
font-family: var(--font-heading);
|
||||
font-size: 1.1rem;
|
||||
font-weight: 700;
|
||||
@include gradient-text(var(--color-accent-light), var(--color-accent));
|
||||
}
|
||||
|
||||
.brand-tagline {
|
||||
font-size: 0.65rem;
|
||||
color: var(--color-medium);
|
||||
letter-spacing: 0.1em;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.navbar-toggle {
|
||||
display: none;
|
||||
flex-direction: column;
|
||||
gap: 4px;
|
||||
background: none;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
padding: $spacing-xs;
|
||||
|
||||
.bar {
|
||||
display: block;
|
||||
width: 24px;
|
||||
height: 2px;
|
||||
background: var(--color-white);
|
||||
border-radius: 1px;
|
||||
transition: $transition-normal;
|
||||
}
|
||||
}
|
||||
|
||||
.navbar-menu {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: $spacing-lg;
|
||||
}
|
||||
|
||||
.nav-links {
|
||||
display: flex;
|
||||
list-style: none;
|
||||
gap: $spacing-md;
|
||||
|
||||
a {
|
||||
color: var(--color-light);
|
||||
font-size: 0.95rem;
|
||||
font-weight: 500;
|
||||
padding: $spacing-xs $spacing-sm;
|
||||
border-radius: $radius-sm;
|
||||
transition: color $transition-fast, background $transition-fast;
|
||||
|
||||
&:hover,
|
||||
&.active {
|
||||
color: var(--color-accent-light);
|
||||
background: rgba(232, 122, 46, 0.1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.btn-donate-nav {
|
||||
@include button-style($accent-orange, $neutral-white, $accent-orange-dark);
|
||||
padding: $spacing-xs $spacing-md;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
// Responsive
|
||||
@media (max-width: #{$bp-md - 1px}) {
|
||||
.navbar-toggle {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.navbar-menu {
|
||||
position: absolute;
|
||||
top: 100%;
|
||||
left: 0;
|
||||
right: 0;
|
||||
background: var(--color-primary-dark);
|
||||
flex-direction: column;
|
||||
padding: $spacing-md;
|
||||
gap: $spacing-md;
|
||||
box-shadow: $shadow-lg;
|
||||
transform: translateY(-10px);
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
transition: transform $transition-normal, opacity $transition-normal;
|
||||
|
||||
&.open {
|
||||
transform: translateY(0);
|
||||
opacity: 1;
|
||||
pointer-events: auto;
|
||||
}
|
||||
}
|
||||
|
||||
.nav-links {
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { RouterLink, RouterLinkActive } from '@angular/router';
|
||||
|
||||
@Component({
|
||||
selector: 'app-navbar',
|
||||
standalone: true,
|
||||
imports: [RouterLink, RouterLinkActive],
|
||||
templateUrl: './navbar.component.html',
|
||||
styleUrl: './navbar.component.scss',
|
||||
})
|
||||
export class NavbarComponent {
|
||||
menuOpen = false;
|
||||
|
||||
toggleMenu(): void {
|
||||
this.menuOpen = !this.menuOpen;
|
||||
}
|
||||
|
||||
closeMenu(): void {
|
||||
this.menuOpen = false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
<section class="schedule">
|
||||
<div class="container">
|
||||
<div class="schedule-header">
|
||||
<img src="assets/svg/small-flower.svg" alt="" class="schedule-flower" aria-hidden="true">
|
||||
<h2>Today's <span class="text-accent">Program Schedule</span></h2>
|
||||
<p class="section-intro">
|
||||
All times are local (Mountain Time). Every show is free to listen to
|
||||
live at 98.7 FM or via our online stream.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="schedule-list">
|
||||
<div class="schedule-day-label">Monday – Friday</div>
|
||||
<div class="schedule-table">
|
||||
<div *ngFor="let program of programs" class="schedule-row">
|
||||
<div class="schedule-time">{{ program.time }}</div>
|
||||
<div class="schedule-divider"></div>
|
||||
<div class="schedule-details">
|
||||
<h4 class="schedule-title">{{ program.title }}</h4>
|
||||
<div class="schedule-meta">
|
||||
<span class="schedule-host">
|
||||
<span aria-hidden="true">🎙️</span> {{ program.host }}
|
||||
</span>
|
||||
<span class="schedule-genre">{{ program.genre }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="schedule-weekend">
|
||||
<div class="weekend-heading">
|
||||
<img src="assets/svg/small-flower.svg" alt="" class="schedule-flower-sm" aria-hidden="true">
|
||||
<h3>Weekend Programming</h3>
|
||||
</div>
|
||||
<div class="weekend-grid">
|
||||
<div class="weekend-card">
|
||||
<div class="card-day">Saturday</div>
|
||||
<div class="card-programs">
|
||||
<div class="card-item">
|
||||
<strong>9:00 AM</strong> — Country Roads Hour
|
||||
</div>
|
||||
<div class="card-item">
|
||||
<strong>11:00 AM</strong> — Community Hour (call-ins welcome!)
|
||||
</div>
|
||||
<div class="card-item">
|
||||
<strong>2:00 PM</strong> — Afternoon Bluegrass
|
||||
</div>
|
||||
<div class="card-item">
|
||||
<strong>4:00 PM</strong> — Record Request Hour
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="weekend-card">
|
||||
<div class="card-day">Sunday</div>
|
||||
<div class="card-programs">
|
||||
<div class="card-item">
|
||||
<strong>10:00 AM</strong> — Sunday Morning Hymns & Folk
|
||||
</div>
|
||||
<div class="card-item">
|
||||
<strong>12:00 PM</strong> — Gospel & Roots
|
||||
</div>
|
||||
<div class="card-item">
|
||||
<strong>3:00 PM</strong> — The Long Wave (ambient / nature sounds)
|
||||
</div>
|
||||
<div class="card-item">
|
||||
<strong>6:00 PM</strong> — Sunday Sunset Jazz
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
@@ -0,0 +1,173 @@
|
||||
@use '../../styles/variables' as *;
|
||||
@use '../../styles/mixins' as *;
|
||||
|
||||
.schedule {
|
||||
padding: $spacing-3xl 0;
|
||||
background: var(--color-white);
|
||||
}
|
||||
|
||||
.schedule-header {
|
||||
text-align: center;
|
||||
margin-bottom: $spacing-2xl;
|
||||
|
||||
.schedule-flower {
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
margin: 0 auto $spacing-md;
|
||||
opacity: 0.5;
|
||||
}
|
||||
}
|
||||
|
||||
.schedule-list {
|
||||
max-width: 800px;
|
||||
margin: 0 auto $spacing-3xl;
|
||||
}
|
||||
|
||||
.schedule-day-label {
|
||||
text-align: center;
|
||||
font-family: var(--font-heading);
|
||||
font-size: 1.2rem;
|
||||
color: var(--color-primary);
|
||||
margin-bottom: $spacing-md;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.schedule-table {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0;
|
||||
}
|
||||
|
||||
.schedule-row {
|
||||
display: flex;
|
||||
align-items: stretch;
|
||||
padding: $spacing-md 0;
|
||||
border-bottom: 1px solid var(--color-light);
|
||||
transition: background $transition-fast;
|
||||
|
||||
&:hover {
|
||||
background: var(--color-cream);
|
||||
}
|
||||
}
|
||||
|
||||
.schedule-time {
|
||||
width: 100px;
|
||||
flex-shrink: 0;
|
||||
font-family: var(--font-mono);
|
||||
font-size: 0.95rem;
|
||||
color: var(--color-accent);
|
||||
font-weight: 600;
|
||||
padding-right: $spacing-md;
|
||||
text-align: right;
|
||||
padding-top: 2px;
|
||||
}
|
||||
|
||||
.schedule-divider {
|
||||
width: 2px;
|
||||
background: var(--color-accent-muted);
|
||||
margin: 0 $spacing-sm;
|
||||
border-radius: 1px;
|
||||
opacity: 0.4;
|
||||
}
|
||||
|
||||
.schedule-details {
|
||||
flex: 1;
|
||||
padding: $spacing-xs 0;
|
||||
}
|
||||
|
||||
.schedule-title {
|
||||
font-size: 1.05rem;
|
||||
color: var(--color-primary);
|
||||
margin-bottom: $spacing-xs;
|
||||
}
|
||||
|
||||
.schedule-meta {
|
||||
display: flex;
|
||||
gap: $spacing-md;
|
||||
font-size: 0.85rem;
|
||||
color: var(--color-medium);
|
||||
|
||||
.schedule-host {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.schedule-genre {
|
||||
background: var(--color-light);
|
||||
padding: 2px 10px;
|
||||
border-radius: 10px;
|
||||
font-style: italic;
|
||||
}
|
||||
}
|
||||
|
||||
// Weekend
|
||||
.schedule-weekend {
|
||||
margin-top: $spacing-xl;
|
||||
}
|
||||
|
||||
.weekend-heading {
|
||||
text-align: center;
|
||||
margin-bottom: $spacing-lg;
|
||||
|
||||
.schedule-flower-sm {
|
||||
width: 35px;
|
||||
height: 35px;
|
||||
margin: 0 auto $spacing-sm;
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: 1.6rem;
|
||||
color: var(--color-primary);
|
||||
}
|
||||
}
|
||||
|
||||
.weekend-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
|
||||
gap: $spacing-lg;
|
||||
}
|
||||
|
||||
.weekend-card {
|
||||
@include card-style;
|
||||
padding: $spacing-xl;
|
||||
background: var(--color-white);
|
||||
|
||||
.card-day {
|
||||
font-family: var(--font-heading);
|
||||
font-size: 1.4rem;
|
||||
font-weight: 700;
|
||||
color: var(--color-accent);
|
||||
margin-bottom: $spacing-md;
|
||||
padding-bottom: $spacing-sm;
|
||||
border-bottom: 2px solid var(--color-light);
|
||||
}
|
||||
|
||||
.card-programs {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: $spacing-sm;
|
||||
}
|
||||
|
||||
.card-item {
|
||||
font-size: 0.95rem;
|
||||
color: var(--color-dark);
|
||||
padding: $spacing-sm;
|
||||
border-radius: $radius-sm;
|
||||
transition: background $transition-fast;
|
||||
|
||||
strong {
|
||||
color: var(--color-primary);
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background: var(--color-cream);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: #{$bp-md - 1px}) {
|
||||
.schedule-time { width: 80px; font-size: 0.85rem; }
|
||||
.weekend-grid { grid-template-columns: 1fr; }
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { NgFor } from '@angular/common';
|
||||
|
||||
interface Program {
|
||||
time: string;
|
||||
title: string;
|
||||
host: string;
|
||||
genre: string;
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'app-schedule',
|
||||
standalone: true,
|
||||
imports: [NgFor],
|
||||
templateUrl: './schedule.component.html',
|
||||
styleUrl: './schedule.component.scss',
|
||||
})
|
||||
export class ScheduleComponent {
|
||||
readonly programs: Program[] = [
|
||||
{ time: '6:00 AM', title: 'Morning Mountain Mist', host: 'Diana Walsh', genre: 'Ambient / Nature' },
|
||||
{ time: '8:00 AM', title: 'Community Roundup', host: 'Tom Breen', genre: 'News / Talk' },
|
||||
{ time: '10:00 AM', title: 'Bluegrass Trails', host: 'Sarah Lynn', genre: 'Bluegrass' },
|
||||
{ time: '12:00 PM', title: 'Lunchtime Jazz', host: 'Mike Darrow', genre: 'Jazz' },
|
||||
{ time: '2:00 PM', title: 'Folk Roots Hour', host: 'Nadia Cole', genre: 'Folk' },
|
||||
{ time: '4:00 PM', title: 'Afternoon Acoustics', host: 'Jen Reeves', genre: 'Acoustic' },
|
||||
{ time: '6:00 PM', title: 'Evening Echoes', host: 'Carlos Mendez', genre: 'Indie / Alternative' },
|
||||
{ time: '8:00 PM', title: 'Classical Mountains', host: 'Elena Cross', genre: 'Classical' },
|
||||
{ time: '10:00 PM', title: 'Night Owl Session', host: 'DJ Kofi', genre: 'Electronic' },
|
||||
{ time: '12:00 AM', title: 'Late Night Jazz', host: 'Mike Darrow', genre: 'Jazz' },
|
||||
];
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1440 80" width="100%" height="80" preserveAspectRatio="none">
|
||||
<defs>
|
||||
<linearGradient id="divGrad1" x1="0%" y1="0%" x2="100%" y2="0%">
|
||||
<stop offset="0%" style="stop-color:#1a3a5c;stop-opacity:0"/>
|
||||
<stop offset="20%" style="stop-color:#1a3a5c;stop-opacity:0.3"/>
|
||||
<stop offset="80%" style="stop-color:#1a3a5c;stop-opacity:0.3"/>
|
||||
<stop offset="100%" style="stop-color:#1a3a5c;stop-opacity:0"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<path d="M0,80 L0,50 Q180,10 360,40 Q540,70 720,40 Q900,10 1080,40 Q1260,70 1440,50 L1440,80 Z" fill="url(#divGrad1)"/>
|
||||
<!-- Small flower accents along divider -->
|
||||
<g transform="translate(360,45) scale(0.3)" opacity="0.4">
|
||||
<ellipse cx="30" cy="12" rx="8" ry="14" fill="#e87a2e" transform="rotate(0,30,30)"/>
|
||||
<ellipse cx="30" cy="12" rx="8" ry="14" fill="#f09a4e" transform="rotate(72,30,30)"/>
|
||||
<ellipse cx="30" cy="12" rx="8" ry="14" fill="#e87a2e" transform="rotate(144,30,30)"/>
|
||||
<ellipse cx="30" cy="12" rx="8" ry="14" fill="#f09a4e" transform="rotate(216,30,30)"/>
|
||||
<ellipse cx="30" cy="12" rx="8" ry="14" fill="#e87a2e" transform="rotate(288,30,30)"/>
|
||||
<circle cx="30" cy="30" r="6" fill="#f5c842"/>
|
||||
</g>
|
||||
<g transform="translate(720,38) scale(0.35)" opacity="0.5">
|
||||
<ellipse cx="30" cy="12" rx="8" ry="14" fill="#e87a2e" transform="rotate(0,30,30)"/>
|
||||
<ellipse cx="30" cy="12" rx="8" ry="14" fill="#f09a4e" transform="rotate(72,30,30)"/>
|
||||
<ellipse cx="30" cy="12" rx="8" ry="14" fill="#e87a2e" transform="rotate(144,30,30)"/>
|
||||
<ellipse cx="30" cy="12" rx="8" ry="14" fill="#f09a4e" transform="rotate(216,30,30)"/>
|
||||
<ellipse cx="30" cy="12" rx="8" ry="14" fill="#e87a2e" transform="rotate(288,30,30)"/>
|
||||
<circle cx="30" cy="30" r="6" fill="#f5c842"/>
|
||||
</g>
|
||||
<g transform="translate(1080,45) scale(0.3)" opacity="0.4">
|
||||
<ellipse cx="30" cy="12" rx="8" ry="14" fill="#e87a2e" transform="rotate(0,30,30)"/>
|
||||
<ellipse cx="30" cy="12" rx="8" ry="14" fill="#f09a4e" transform="rotate(72,30,30)"/>
|
||||
<ellipse cx="30" cy="12" rx="8" ry="14" fill="#e87a2e" transform="rotate(144,30,30)"/>
|
||||
<ellipse cx="30" cy="12" rx="8" ry="14" fill="#f09a4e" transform="rotate(216,30,30)"/>
|
||||
<ellipse cx="30" cy="12" rx="8" ry="14" fill="#e87a2e" transform="rotate(288,30,30)"/>
|
||||
<circle cx="30" cy="30" r="6" fill="#f5c842"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.4 KiB |
@@ -0,0 +1,31 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1440 400" preserveAspectRatio="none" width="100%" height="100%">
|
||||
<defs>
|
||||
<linearGradient id="mountainGrad1" x1="0%" y1="0%" x2="0%" y2="100%">
|
||||
<stop offset="0%" style="stop-color:#2a5a8c;stop-opacity:0.9"/>
|
||||
<stop offset="100%" style="stop-color:#1a3a5c;stop-opacity:1"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="mountainGrad2" x1="0%" y1="0%" x2="0%" y2="100%">
|
||||
<stop offset="0%" style="stop-color:#3a6a9c;stop-opacity:0.7"/>
|
||||
<stop offset="100%" style="stop-color:#2a5a8c;stop-opacity:0.8"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="mountainGrad3" x1="0%" y1="0%" x2="0%" y2="100%">
|
||||
<stop offset="0%" style="stop-color:#0e2440;stop-opacity:0.6"/>
|
||||
<stop offset="100%" style="stop-color:#1a3a5c;stop-opacity:0.7"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="snowGrad" x1="0%" y1="0%" x2="0%" y2="100%">
|
||||
<stop offset="0%" style="stop-color:#ffffff;stop-opacity:0.9"/>
|
||||
<stop offset="100%" style="stop-color:#e8e8e8;stop-opacity:0.3"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<!-- Far mountains -->
|
||||
<path d="M0,400 L0,280 L120,200 L240,260 L360,150 L480,230 L540,180 L600,210 L720,120 L840,200 L960,160 L1080,220 L1200,140 L1320,200 L1440,170 L1440,400 Z" fill="url(#mountainGrad3)"/>
|
||||
<!-- Mid mountains -->
|
||||
<path d="M0,400 L0,320 L180,240 L300,300 L420,180 L540,270 L660,200 L780,280 L900,170 L1020,260 L1140,210 L1260,270 L1380,220 L1440,250 L1440,400 Z" fill="url(#mountainGrad2)"/>
|
||||
<!-- Near mountains (prominent) -->
|
||||
<path d="M0,400 L0,340 L160,280 L280,330 L400,200 L500,280 L600,220 L700,290 L820,190 L920,260 L1040,210 L1160,280 L1280,230 L1360,280 L1440,260 L1440,400 Z" fill="url(#mountainGrad1)"/>
|
||||
<!-- Snow caps -->
|
||||
<path d="M400,200 L385,215 L415,215 Z" fill="url(#snowGrad)" opacity="0.7"/>
|
||||
<path d="M820,190 L805,208 L835,208 Z" fill="url(#snowGrad)" opacity="0.7"/>
|
||||
<path d="M1280,230 L1265,248 L1295,248 Z" fill="url(#snowGrad)" opacity="0.6"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.0 KiB |
@@ -0,0 +1,36 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 200" width="200" height="200">
|
||||
<defs>
|
||||
<radialGradient id="petalGrad" cx="50%" cy="40%" r="50%">
|
||||
<stop offset="0%" style="stop-color:#f0a86a"/>
|
||||
<stop offset="100%" style="stop-color:#e87a2e"/>
|
||||
</radialGradient>
|
||||
<radialGradient id="centerGrad" cx="45%" cy="40%" r="50%">
|
||||
<stop offset="0%" style="stop-color:#f5c842"/>
|
||||
<stop offset="100%" style="stop-color:#d4941a"/>
|
||||
</radialGradient>
|
||||
</defs>
|
||||
<!-- Stem and leaves -->
|
||||
<path d="M100,160 Q95,180 98,198" stroke="#4a7a3e" stroke-width="3" fill="none" stroke-linecap="round"/>
|
||||
<path d="M98,175 Q75,165 65,170 Q78,180 98,175" fill="#5a8a4e" opacity="0.8"/>
|
||||
<path d="M99,185 Q125,178 135,182 Q122,192 99,185" fill="#5a8a4e" opacity="0.8"/>
|
||||
<!-- Outer petals -->
|
||||
<ellipse cx="100" cy="50" rx="22" ry="35" fill="url(#petalGrad)" transform="rotate(0,100,90)" opacity="0.9"/>
|
||||
<ellipse cx="100" cy="50" rx="22" ry="35" fill="url(#petalGrad)" transform="rotate(45,100,90)" opacity="0.9"/>
|
||||
<ellipse cx="100" cy="50" rx="22" ry="35" fill="url(#petalGrad)" transform="rotate(90,100,90)" opacity="0.9"/>
|
||||
<ellipse cx="100" cy="50" rx="22" ry="35" fill="url(#petalGrad)" transform="rotate(135,100,90)" opacity="0.9"/>
|
||||
<ellipse cx="100" cy="50" rx="22" ry="35" fill="url(#petalGrad)" transform="rotate(180,100,90)" opacity="0.9"/>
|
||||
<ellipse cx="100" cy="50" rx="22" ry="35" fill="url(#petalGrad)" transform="rotate(225,100,90)" opacity="0.9"/>
|
||||
<ellipse cx="100" cy="50" rx="22" ry="35" fill="url(#petalGrad)" transform="rotate(270,100,90)" opacity="0.9"/>
|
||||
<ellipse cx="100" cy="50" rx="22" ry="35" fill="url(#petalGrad)" transform="rotate(315,100,90)" opacity="0.9"/>
|
||||
<!-- Inner petals -->
|
||||
<ellipse cx="100" cy="65" rx="14" ry="22" fill="#f09a4e" transform="rotate(22,100,90)" opacity="0.8"/>
|
||||
<ellipse cx="100" cy="65" rx="14" ry="22" fill="#f09a4e" transform="rotate(97,100,90)" opacity="0.8"/>
|
||||
<ellipse cx="100" cy="65" rx="14" ry="22" fill="#f09a4e" transform="rotate(172,100,90)" opacity="0.8"/>
|
||||
<ellipse cx="100" cy="65" rx="14" ry="22" fill="#f09a4e" transform="rotate(247,100,90)" opacity="0.8"/>
|
||||
<ellipse cx="100" cy="65" rx="14" ry="22" fill="#f09a4e" transform="rotate(322,100,90)" opacity="0.8"/>
|
||||
<!-- Flower center -->
|
||||
<circle cx="100" cy="90" r="18" fill="url(#centerGrad)"/>
|
||||
<circle cx="100" cy="90" r="12" fill="#d4941a" opacity="0.5"/>
|
||||
<circle cx="100" cy="90" r="6" fill="#b87a10" opacity="0.4"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.5 KiB |
@@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 60 60" width="60" height="60">
|
||||
<g>
|
||||
<ellipse cx="30" cy="12" rx="8" ry="14" fill="#e87a2e" transform="rotate(0,30,30)" opacity="0.85"/>
|
||||
<ellipse cx="30" cy="12" rx="8" ry="14" fill="#f09a4e" transform="rotate(72,30,30)" opacity="0.85"/>
|
||||
<ellipse cx="30" cy="12" rx="8" ry="14" fill="#e87a2e" transform="rotate(144,30,30)" opacity="0.85"/>
|
||||
<ellipse cx="30" cy="12" rx="8" ry="14" fill="#f09a4e" transform="rotate(216,30,30)" opacity="0.85"/>
|
||||
<ellipse cx="30" cy="12" rx="8" ry="14" fill="#e87a2e" transform="rotate(288,30,30)" opacity="0.85"/>
|
||||
<circle cx="30" cy="30" r="6" fill="#f5c842"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 721 B |
@@ -0,0 +1,13 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>RadioStation</title>
|
||||
<base href="/" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<link rel="icon" type="image/x-icon" href="favicon.ico" />
|
||||
</head>
|
||||
<body>
|
||||
<app-root></app-root>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,5 @@
|
||||
import { bootstrapApplication } from '@angular/platform-browser';
|
||||
import { appConfig } from './app/app.config';
|
||||
import { App } from './app/app';
|
||||
|
||||
bootstrapApplication(App, appConfig).catch((err) => console.error(err));
|
||||
+102
@@ -0,0 +1,102 @@
|
||||
// ===== Global style entry point ======
|
||||
// All SCSS partials are imported here. To change the color scheme,
|
||||
// only edit _variables.scss — every component inherits from it.
|
||||
|
||||
@use './styles/variables' as *;
|
||||
@use './styles/mixins' as *;
|
||||
@use './styles/themes';
|
||||
|
||||
// ===== Base reset and global styles =====
|
||||
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
html {
|
||||
font-size: 16px;
|
||||
scroll-behavior: smooth;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: var(--font-primary);
|
||||
color: var(--color-dark);
|
||||
background-color: var(--color-cream);
|
||||
line-height: 1.6;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
h1, h2, h3, h4, h5, h6 {
|
||||
font-family: var(--font-heading);
|
||||
color: var(--color-primary);
|
||||
line-height: 1.2;
|
||||
margin-bottom: $spacing-md;
|
||||
}
|
||||
|
||||
h1 { font-size: 2.8rem; }
|
||||
h2 { font-size: 2.2rem; }
|
||||
h3 { font-size: 1.6rem; }
|
||||
|
||||
a {
|
||||
color: var(--color-accent);
|
||||
text-decoration: none;
|
||||
transition: color $transition-fast;
|
||||
|
||||
&:hover {
|
||||
color: var(--color-accent-dark);
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
|
||||
img, svg {
|
||||
max-width: 100%;
|
||||
height: auto;
|
||||
display: block;
|
||||
}
|
||||
|
||||
// Utility classes
|
||||
.container {
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
padding: 0 $spacing-lg;
|
||||
}
|
||||
|
||||
.text-center { text-align: center; }
|
||||
.text-accent { color: var(--color-accent); }
|
||||
|
||||
.section-intro {
|
||||
max-width: 700px;
|
||||
margin: 0 auto $spacing-2xl;
|
||||
text-align: center;
|
||||
font-size: 1.1rem;
|
||||
color: var(--color-medium);
|
||||
}
|
||||
|
||||
.btn {
|
||||
@include button-style($accent-orange, $neutral-white);
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: $spacing-xs;
|
||||
text-decoration: none;
|
||||
font-family: var(--font-primary);
|
||||
letter-spacing: 0.02em;
|
||||
}
|
||||
|
||||
.btn-secondary {
|
||||
@include button-style($primary-blue, $neutral-white, $primary-blue-dark);
|
||||
}
|
||||
|
||||
.btn-outline {
|
||||
background: transparent;
|
||||
border: 2px solid $accent-orange;
|
||||
color: $accent-orange;
|
||||
|
||||
&:hover {
|
||||
background: $accent-orange;
|
||||
color: $neutral-white;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
@use './variables' as *;
|
||||
|
||||
// ========== Reusable SCSS mixins for layout and styling ==========
|
||||
|
||||
@mixin flex-center {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
@mixin flex-between {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
@mixin gradient-text($from: $accent-orange, $to: $accent-orange-light) {
|
||||
background: linear-gradient(135deg, $from, $to);
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
background-clip: text;
|
||||
}
|
||||
|
||||
@mixin card-style {
|
||||
background: $neutral-white;
|
||||
border-radius: $radius-lg;
|
||||
box-shadow: $shadow-md;
|
||||
transition: transform $transition-normal, box-shadow $transition-normal;
|
||||
|
||||
&:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: $shadow-lg;
|
||||
}
|
||||
}
|
||||
|
||||
@mixin section-padding($top: $spacing-3xl, $bottom: $spacing-3xl) {
|
||||
padding-top: $top;
|
||||
padding-bottom: $bottom;
|
||||
}
|
||||
|
||||
@mixin responsive($breakpoint) {
|
||||
@if $breakpoint == sm { @media (max-width: ($bp-sm - 1px)) { @content; } }
|
||||
@if $breakpoint == md { @media (max-width: ($bp-md - 1px)) { @content; } }
|
||||
@if $breakpoint == lg { @media (max-width: ($bp-lg - 1px)) { @content; } }
|
||||
@if $breakpoint == xl { @media (max-width: ($bp-xl - 1px)) { @content; } }
|
||||
}
|
||||
|
||||
@mixin button-style($bg: $accent-orange, $text: $neutral-white, $hover-bg: $accent-orange-dark) {
|
||||
background: $bg;
|
||||
color: $text;
|
||||
border: none;
|
||||
border-radius: $radius-md;
|
||||
padding: $spacing-sm $spacing-lg;
|
||||
font-size: 1rem;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
transition: background $transition-fast, transform $transition-fast;
|
||||
|
||||
&:hover {
|
||||
background: $hover-bg;
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
&:active {
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
@mixin mountain-divider($color: $primary-blue, $height: 80px) {
|
||||
content: '';
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: $height;
|
||||
background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1440 320'%3E%3Cpath fill='%231a3a5c' fill-opacity='1' d='M0,224L48,213.3C96,203,192,181,288,181.3C384,181,480,203,576,218.7C672,235,768,245,864,234.7C960,224,1056,192,1152,186.7C1248,181,1344,203,1392,213.3L1440,224L1440,320L1392,320C1344,320,1248,320,1152,320C1056,320,960,320,864,320C768,320,672,320,576,320C480,320,384,320,288,320C192,320,96,320,48,320L0,320Z'%3E%3C/path%3E%3C/svg%3E") no-repeat center bottom;
|
||||
background-size: cover;
|
||||
margin-top: -$height;
|
||||
}
|
||||
|
||||
@mixin flowery-border($color: $accent-orange) {
|
||||
position: relative;
|
||||
|
||||
&::after {
|
||||
content: '';
|
||||
display: block;
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
margin: $spacing-md auto 0;
|
||||
background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'%3E%3Ccircle cx='50' cy='35' r='12' fill='%23e87a2e'/%3E%3Ccircle cx='35' cy='50' r='12' fill='%23e87a2e'/%3E%3Ccircle cx='65' cy='50' r='12' fill='%23e87a2e'/%3E%3Ccircle cx='40' cy='62' r='12' fill='%23e87a2e'/%3E%3Ccircle cx='60' cy='62' r='12' fill='%23e87a2e'/%3E%3Ccircle cx='50' cy='50' r='8' fill='%23f0a86a'/%3E%3C/svg%3E") no-repeat center;
|
||||
background-size: contain;
|
||||
opacity: 0.6;
|
||||
}
|
||||
}
|
||||
|
||||
@mixin fade-in {
|
||||
animation: fadeIn 0.6s ease-in;
|
||||
}
|
||||
|
||||
@keyframes fadeIn {
|
||||
from { opacity: 0; transform: translateY(10px); }
|
||||
to { opacity: 1; transform: translateY(0); }
|
||||
}
|
||||
|
||||
@keyframes float {
|
||||
0%, 100% { transform: translateY(0); }
|
||||
50% { transform: translateY(-8px); }
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
@use './variables' as *;
|
||||
|
||||
// ========== CSS Custom Properties (exposed to the browser) ==========
|
||||
// These map SCSS variables to CSS custom properties so Angular components
|
||||
// can consume them via var() at runtime.
|
||||
|
||||
:root {
|
||||
// Primary
|
||||
--color-primary: #{$primary-blue};
|
||||
--color-primary-light: #{$primary-blue-light};
|
||||
--color-primary-dark: #{$primary-blue-dark};
|
||||
--color-primary-muted: #{$primary-blue-muted};
|
||||
|
||||
// Accent
|
||||
--color-accent: #{$accent-orange};
|
||||
--color-accent-light: #{$accent-orange-light};
|
||||
--color-accent-dark: #{$accent-orange-dark};
|
||||
--color-accent-muted: #{$accent-orange-muted};
|
||||
|
||||
// Neutrals
|
||||
--color-white: #{$neutral-white};
|
||||
--color-cream: #{$neutral-cream};
|
||||
--color-light: #{$neutral-light};
|
||||
--color-medium: #{$neutral-medium};
|
||||
--color-dark: #{$neutral-dark};
|
||||
--color-black: #{$neutral-black};
|
||||
|
||||
// Semantic
|
||||
--color-success: #{$success-green};
|
||||
--color-danger: #{$danger-red};
|
||||
--color-info: #{$info-blue};
|
||||
|
||||
// Typography
|
||||
--font-primary: #{$font-primary};
|
||||
--font-heading: #{$font-heading};
|
||||
--font-mono: #{$font-mono};
|
||||
|
||||
// Radii
|
||||
--radius-sm: #{$radius-sm};
|
||||
--radius-md: #{$radius-md};
|
||||
--radius-lg: #{$radius-lg};
|
||||
--radius-xl: #{$radius-xl};
|
||||
--radius-full: #{$radius-full};
|
||||
|
||||
// Shadows
|
||||
--shadow-sm: #{$shadow-sm};
|
||||
--shadow-md: #{$shadow-md};
|
||||
--shadow-lg: #{$shadow-lg};
|
||||
--shadow-xl: #{$shadow-xl};
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
// =============================================================================
|
||||
// Color Palette — edit these to change the entire site's color scheme
|
||||
// =============================================================================
|
||||
|
||||
// Primary palette
|
||||
$primary-blue: #1a3a5c;
|
||||
$primary-blue-light: #2a5a8c;
|
||||
$primary-blue-dark: #0e2440;
|
||||
$primary-blue-muted: #3a6a9c;
|
||||
|
||||
// Accent palette
|
||||
$accent-orange: #e87a2e;
|
||||
$accent-orange-light: #f09a4e;
|
||||
$accent-orange-dark: #c85a1e;
|
||||
$accent-orange-muted: #f0a86a;
|
||||
|
||||
// Neutrals
|
||||
$neutral-white: #ffffff;
|
||||
$neutral-cream: #faf6f0;
|
||||
$neutral-light: #f0ebe3;
|
||||
$neutral-medium: #8a8580;
|
||||
$neutral-dark: #3a3632;
|
||||
$neutral-black: #1a1816;
|
||||
|
||||
// Semantic
|
||||
$success-green: #4a9e4f;
|
||||
$danger-red: #c83030;
|
||||
$info-blue: #3a8abf;
|
||||
|
||||
// Gradients
|
||||
$sky-gradient: linear-gradient(135deg, $primary-blue-dark 0%, $primary-blue 40%, $primary-blue-light 100%);
|
||||
$sunset-gradient: linear-gradient(135deg, $accent-orange-dark 0%, $accent-orange 50%, $accent-orange-light 100%);
|
||||
$mixed-gradient: linear-gradient(135deg, $primary-blue-dark 0%, $primary-blue 50%, $accent-orange 100%);
|
||||
|
||||
// Typography
|
||||
$font-primary: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
||||
$font-heading: 'Georgia', 'Times New Roman', serif;
|
||||
$font-mono: 'Courier New', Courier, monospace;
|
||||
|
||||
// Spacing
|
||||
$spacing-xs: 0.25rem;
|
||||
$spacing-sm: 0.5rem;
|
||||
$spacing-md: 1rem;
|
||||
$spacing-lg: 2rem;
|
||||
$spacing-xl: 3rem;
|
||||
$spacing-2xl: 4rem;
|
||||
$spacing-3xl: 6rem;
|
||||
|
||||
// Border radius
|
||||
$radius-sm: 4px;
|
||||
$radius-md: 8px;
|
||||
$radius-lg: 16px;
|
||||
$radius-xl: 24px;
|
||||
$radius-full: 50%;
|
||||
|
||||
// Shadows
|
||||
$shadow-sm: 0 1px 3px rgba(0,0,0,0.12);
|
||||
$shadow-md: 0 4px 12px rgba(0,0,0,0.15);
|
||||
$shadow-lg: 0 8px 30px rgba(0,0,0,0.18);
|
||||
$shadow-xl: 0 12px 40px rgba(0,0,0,0.22);
|
||||
|
||||
// Breakpoints
|
||||
$bp-sm: 576px;
|
||||
$bp-md: 768px;
|
||||
$bp-lg: 992px;
|
||||
$bp-xl: 1200px;
|
||||
|
||||
// Transitions
|
||||
$transition-fast: 150ms ease;
|
||||
$transition-normal: 300ms ease;
|
||||
$transition-slow: 500ms ease;
|
||||
|
||||
// Z-index scale
|
||||
$z-dropdown: 100;
|
||||
$z-sticky: 200;
|
||||
$z-overlay: 300;
|
||||
$z-modal: 400;
|
||||
$z-toast: 500;
|
||||
Reference in New Issue
Block a user