diff --git a/DeepDrftPublic.Client/Layout/Pages.cs b/DeepDrftPublic.Client/Layout/Pages.cs index 54d3320..1cb6eb8 100644 --- a/DeepDrftPublic.Client/Layout/Pages.cs +++ b/DeepDrftPublic.Client/Layout/Pages.cs @@ -36,6 +36,7 @@ public static class Pages new() { Name = "Mixes", Route = "/mixes", Icon = Icons.Material.Filled.GraphicEq }, ], }, + new() { Name = "About", Route = "/about", Icon = Icons.Material.Filled.Groups }, ]; public static readonly List AllPages = diff --git a/DeepDrftPublic.Client/Pages/About.razor b/DeepDrftPublic.Client/Pages/About.razor new file mode 100644 index 0000000..5b83874 --- /dev/null +++ b/DeepDrftPublic.Client/Pages/About.razor @@ -0,0 +1,321 @@ +@page "/about" +@using DeepDrftPublic.Client.Controls + +The Collective - Deep DRFT + +@* ── HERO (split 50/50) — reuses the .hero-* type classes with About's own words. + NOT DeepDrftHero (that hard-codes the Deep/DRFT masthead + streaming CTA). ── *@ +
+ + +
+
Charleston, South Carolina
+

The
Collective

+

+ Two people, many hats. We bring the heart and soul of Midwest deep house to Charleston — informed by the founders of the style, and promising to push it forward. +

+
+
+ + + @* IMG SLOT A — hero duo portrait. Reuses the committed duo pair as interim. *@ +
+ +
+
+
+ + @* IMG SLOT B — full-bleed band under the hero, bw+colour crossfade pair. *@ + +
+ +@* ════════════════════ MOVEMENT ONE — THE PEOPLE (pathos) ════════════════════ *@ +
+
+
The People
+
+
+ +@* People intro — two-column section: label + serif title left, prose right. *@ +
+
+ + + +

Two of Us,
No Fixed
Roles

+
+ +
+

+ We met trading synthesizers and found out we were seeking the same thing. Two of us, no fixed roles — we both write, arrange, produce, mix, record in the field, build the visuals, and make the tools when the tools don't exist yet. +

+
+
+
+
+ + @* Member bio pair — two cards side by side; each composes with the body absent + (Khabran ships with an empty body slot, same null-renders-nothing discipline + as ReleaseDescription). *@ + + @foreach (var member in _members) + { + +
+
+ @if (member.PortraitImage1 is not null) + { + + } + else + { + @* Graceful-degrade placeholder until a portrait file lands. *@ + + } +
+
+
@member.Name
+
@member.Role
+ @if (!string.IsNullOrWhiteSpace(member.Bio)) + { +

@member.Bio

+ } +
+
+
+ } +
+
+ +@* ════════════════════ MOVEMENT TWO — THE PROCESS (logos) ════════════════════ *@ +
+
+
The Process
+
+
+ +@* Dark feature band — gear-stage cards. The dark ground carries the analytical register. *@ +
+ +

+ Digital, Analog,
Whatever Moves +

+ +

+ It doesn't matter how — digital or analog, hard or soft, bought or built — as long as it moves the room. The soul in this music is designed, not extracted; assembled, not distilled. +

+ +
+
+
+ +
+
Sketch
+
A loop starts on the Force or the MPC, hands on the pads. The idea has to survive first contact before anything else gets built around it.
+
+
+
+ +
+
Arrange
+
Sometimes into Ableton, sometimes start-to-finish in REAPER. The track gets shaped wherever it wants to go — we follow the take, not the template.
+
+
+
+ +
+
Studio
+
A deep bench of synths, drum machines, and pedals; digital and analog, hard and soft, some of it built by hand. If the sound we need doesn't exist yet, we make the thing that makes it.
+
+
+
+ +
+
Live Rig
+
No laptop, no safety net. A full spread of hardware patched together and played 100% live — sequenced, twisted, and pushed in the moment. Built for the room, the warehouse, the night that doesn't repeat.
+
+
+
+ +@* IMG SLOT D — hands-on-gear band, the literal proof-of-effort image. *@ +
+ +
+ +@* ════════════════════ MOVEMENT THREE — THE PRODUCT (ethos) ════════════════════ *@ +
+
+
The Product
+
+
+ +@* Product intro — two-column section framing the catalogue as evidence. *@ +
+
+ + + +

Classics,
with a
Twist

+
+ +
+

+ Everything ends up here, in the catalogue. It's proof people in Charleston are pushing the sound of the club. +

+
+
+
+
+ + @* Medium triptych — one-line frame of each medium; definitions, not a re-pitch. *@ + +
+ +@* The live turn — "on the street, in the swamp": the identity beyond the releases. *@ +
+ + +
+
Beyond the Releases
+

On the Street,
in the Swamp

+

+ But that's just the releases. We're also out there — on the street, in the swamp, with a PA, a generator, and a bunch of good vibes. +

+
+
+ + +
+ +
+
+
+
+ +@* ── Closing CTA into the catalogue ── *@ +
+
+

Hear the
Proof

+

The catalogue is the evidence. Start listening.

+
+ +
+ +@* IMG SLOT E — closing atmosphere band. *@ +
+ +
+ +@code { + private string AnimClass => RendererInfo.IsInteractive ? string.Empty : "fade-up"; + + // Member bios. Khabran's body is an intentional empty slot — the card composes + // without it (graceful degrade). Daniel's copy is verbatim per spec COPY C, + // including the two typos he chose to keep ("embarked in", "metalhead at from"). + // PortraitImage* are null until final portrait files land — the card renders a + // placeholder treatment in their absence. + private record Member( + string Name, + string Role, + string? Bio, + string? PortraitImage1 = null, + string? PortraitImage2 = null); + + private readonly Member[] _members = + [ + new( + Name: "Khabran Peters", + Role: "Production · Sound Design · Live", + Bio: null), + new( + Name: "Daniel Harvey", + Role: "Production · Sound Design · Live", + Bio: "Daniel started on drums at ten and embarked in electronic music at seventeen — synthesizers first. A metalhead at from a young age, he spent ten years as an engineer living near Detroit filling the nights with synthesized tones and rhythms, shaped most of all by modern underground Detroit techno. Art & engineering cannot be separated: custom plugins, hardware recording & performance rigs, the tools behind the tracks are just as important as the finished sound. To him the science and the math matter as much as the beauty — tension and release, built deliberately."), + ]; +} diff --git a/DeepDrftPublic.Client/Pages/About.razor.css b/DeepDrftPublic.Client/Pages/About.razor.css new file mode 100644 index 0000000..185a27f --- /dev/null +++ b/DeepDrftPublic.Client/Pages/About.razor.css @@ -0,0 +1,641 @@ +/* About.razor scoped styles. + + The About page is built entirely in the Home page's visual language. Those section + primitives (.hero-*, .section, .section-divider, .section-dark, .section-split, + .medium-*, .cta-*, .feature-*) live SCOPED in Home.razor.css and DeepDrftHero.razor.css + — they are not in the global stylesheet, so Blazor CSS isolation will not share them + with this component. The primitives are therefore re-declared here, verbatim from those + sources, so About renders identically without touching Home's rendering surface. The only + genuinely new styling is the two bio-card pieces (.bio-*) at the end. */ + +/* ── Animations (from DeepDrftHero.razor.css) ── */ +@keyframes fade-up { + from { opacity: 0; transform: translateY(24px); } + to { opacity: 1; transform: none; } +} + +.fade-up { + opacity: 0; + animation: fade-up 0.8s ease forwards; +} + +/* ── HERO (from Home.razor.css + DeepDrftHero.razor.css) ── */ +.hero { + min-height: 100vh; + overflow: hidden; +} + +.hero-left { + display: flex; + flex-direction: column; + justify-content: center; + padding: 6rem 3rem; + position: relative; + background: var(--deepdrft-white); + height: 100%; +} + +.hero-image-pane { + display: flex; + flex-direction: column; + justify-content: center; + background: var(--deepdrft-white); + height: 100%; +} + +@media (max-width: 960px) { + .hero { min-height: auto; } + .hero-left { padding: 4rem 1.5rem 3rem; } +} + +.hero-eyebrow { + font-family: var(--deepdrft-font-mono); + font-size: 0.65rem; + letter-spacing: 0.28em; + color: var(--deepdrft-green-accent); + text-transform: uppercase; + margin-bottom: 1.8rem; + display: flex; + align-items: center; + gap: 1rem; + animation-delay: 0.1s; +} + +.hero-eyebrow::before { + content: ''; + display: block; + width: 2.5rem; + height: 1px; + background: var(--deepdrft-green-accent); +} + +.hero-title { + font-family: var(--deepdrft-font-display); + font-size: clamp(4.5rem, 8vw, 8.5rem); + font-weight: 300; + line-height: 0.92; + letter-spacing: -0.02em; + color: var(--deepdrft-navy); + margin-bottom: 0.5rem; + animation-delay: 0.22s; +} + +.hero-title em { + font-style: italic; + color: var(--deepdrft-green); +} + +.hero-desc { + font-family: var(--deepdrft-font-body); + font-size: 0.92rem; + line-height: 1.75; + color: var(--deepdrft-navy); + opacity: 0.7; + max-width: 36ch; + margin-bottom: 3rem; + animation-delay: 0.44s; +} + +/* ── DIVIDER (from Home.razor.css) ── */ +.section-divider { + display: flex; + align-items: center; + gap: 2rem; + padding: 2rem 3rem; + background: var(--deepdrft-white); +} + +.divider-line { + flex: 1; + height: 1px; + background: var(--deepdrft-border); +} + +.divider-tag { + font-family: var(--deepdrft-font-mono); + font-size: 0.6rem; + letter-spacing: 0.25em; + color: var(--deepdrft-muted); + text-transform: uppercase; + white-space: nowrap; +} + +/* ── SECTION (from Home.razor.css) ── */ +.section { + padding: 7rem 3rem; + background: var(--deepdrft-white); +} + +@media (min-width: 960px) { + .section-header-grid { + align-items: end; + } +} + +.section-label { + font-family: var(--deepdrft-font-mono); + font-size: 0.62rem; + letter-spacing: 0.28em; + color: var(--deepdrft-green-accent); + text-transform: uppercase; + margin-bottom: 1.2rem; +} + +.section-title { + font-family: var(--deepdrft-font-display); + font-size: clamp(2.8rem, 5vw, 4.5rem); + font-weight: 300; + line-height: 1; + color: var(--deepdrft-navy); +} + +.section-title em { + font-style: italic; + color: var(--deepdrft-green); +} + +/* ::deep required: the class is on the MudItem-rendered div, which does not carry + this component's scope attribute. */ +.section-header-grid ::deep .section-body-item { + display: flex; + align-items: center; +} + +.section-body { + display: flex; + max-width: 560px; + margin: auto; + align-content: center; + justify-content: center; +} + +.section-body p { + display: flex; + font-family: var(--deepdrft-font-body); + font-size: 0.9rem; + line-height: 1.8; + color: var(--deepdrft-navy); + opacity: 0.65; + max-width: 52ch; +} + +/* ── MEDIUM GRID (from Home.razor.css) ── */ +.medium-grid { + display: grid; + grid-template-columns: repeat(3, 1fr); + gap: 56px; + margin-bottom: 4rem; +} + +@media (max-width: 959px) { + .medium-grid { grid-template-columns: repeat(2, 1fr); } + .medium-card:last-child { grid-column: 1 / -1; } +} + +@media (max-width: 599px) { + .medium-grid { grid-template-columns: 1fr; } + .medium-card:last-child { grid-column: auto; } +} + +.medium-card { + background: var(--deepdrft-white); + border: 1px solid var(--deepdrft-border); + cursor: pointer; + overflow: hidden; + text-decoration: none; + display: block; + position: relative; + max-width: 380px; + margin: 0 auto; +} + +.medium-card::after { + content: ''; + position: absolute; + bottom: 0; + left: 0; + right: 0; + height: 2px; + background: var(--deepdrft-green-accent); + transform: scaleX(0); + transform-origin: left; + transition: transform 0.3s; + z-index: 1; +} + +.medium-card:hover::after { transform: scaleX(1); } + +.medium-image { + position: relative; + width: 100%; + aspect-ratio: 4 / 3; + background-size: cover; + background-position: center; + transition: transform 0.5s ease; +} + +.medium-card:hover .medium-image { transform: scale(1.05); } + +.medium-scrim { + position: absolute; + inset: 0; + background: linear-gradient(to bottom, + rgba(17, 35, 56, 0.0) 40%, + rgba(17, 35, 56, 0.35) 100%); + transition: opacity 0.3s; + opacity: 0.7; +} + +.medium-card:hover .medium-scrim { opacity: 1; } + +.medium-body { + padding: 2rem 1.5rem; + position: relative; +} + +.medium-type { + font-family: var(--deepdrft-font-mono); + font-size: 0.58rem; + letter-spacing: 0.2em; + color: var(--deepdrft-muted); + text-transform: uppercase; + margin-bottom: 0.6rem; +} + +.medium-name { + font-family: var(--deepdrft-font-display); + font-size: 1.6rem; + font-weight: 400; + color: var(--deepdrft-navy); + margin-bottom: 0.75rem; + line-height: 1.1; +} + +.medium-desc { + font-family: var(--deepdrft-font-body); + font-size: 0.82rem; + line-height: 1.65; + color: var(--deepdrft-navy); + opacity: 0.6; +} + +/* ── DARK FEATURE SECTION (from Home.razor.css) ── */ +.section-dark { + background: var(--deepdrft-navy); + padding: 7rem 3rem; + color: var(--deepdrft-white); +} + +.section-label-dark { + color: var(--deepdrft-green-accent); +} + +.section-title-dark { + color: var(--deepdrft-white); + margin-top: 0.5rem; +} + +.section-title-dark em { + font-style: italic; + color: var(--deepdrft-green-accent); +} + +/* Process standfirst (COPY D-intro) — sits between the dark title and the gear cards. */ +.section-dark-standfirst { + font-family: var(--deepdrft-font-body); + font-size: 0.92rem; + line-height: 1.8; + color: rgba(250, 250, 248, 0.55); + max-width: 56ch; + margin-top: 2rem; +} + +.features-grid { + display: grid; + grid-template-columns: repeat(4, 1fr); + gap: 0; + border: 1px solid rgba(250, 250, 248, 0.08); + margin-top: 4rem; +} + +.feature-card { + padding: 2.5rem; + border-right: 1px solid rgba(250, 250, 248, 0.08); + transition: background 0.3s; +} + +.feature-card:last-child { border-right: none; } + +.feature-card:hover { background: rgba(250, 250, 248, 0.04); } + +@media (max-width: 960px) { + .features-grid { grid-template-columns: repeat(2, 1fr); } + .feature-card { border-right: none; border-bottom: 1px solid rgba(250, 250, 248, 0.08); } + .feature-card:last-child { border-bottom: none; } +} + +@media (max-width: 599px) { + .features-grid { grid-template-columns: 1fr; } + .feature-card { border-right: none; border-bottom: 1px solid rgba(250, 250, 248, 0.08); } + .feature-card:last-child { border-bottom: none; } +} + +.feature-icon { + width: 2.5rem; + height: 2.5rem; + border: 1px solid rgba(250, 250, 248, 0.15); + margin-bottom: 1.8rem; + display: flex; + align-items: center; + justify-content: center; +} + +.feature-icon svg { + width: 1rem; + height: 1rem; + stroke: var(--deepdrft-green-accent); + fill: none; + stroke-width: 1.5; +} + +.feature-title { + font-family: var(--deepdrft-font-display); + font-size: 1.3rem; + font-weight: 400; + color: var(--deepdrft-white); + margin-bottom: 0.8rem; + line-height: 1.2; +} + +.feature-desc { + font-family: var(--deepdrft-font-body); + font-size: 0.8rem; + line-height: 1.7; + color: rgba(250, 250, 248, 0.45); +} + +/* ── SPLIT (from Home.razor.css) ── */ +.section-split { + min-height: 60vh; +} + +@media (max-width: 960px) { + .section-split { min-height: auto; } +} + +.split-left { + background: var(--deepdrft-green); + padding: 6rem 4rem; + display: flex; + flex-direction: column; + justify-content: center; + position: relative; + overflow: hidden; + height: 100%; +} + +.split-left::before { + content: ''; + position: absolute; + top: -100px; + right: -100px; + width: 400px; + height: 400px; + border-radius: 50%; + background: rgba(61, 122, 104, 0.3); +} + +.split-right { + display: flex; + flex-direction: column; + justify-content: center; + background: var(--deepdrft-white); + height: 100%; +} + +.split-eyebrow { + font-family: var(--deepdrft-font-mono); + font-size: 0.62rem; + letter-spacing: 0.28em; + color: rgba(250, 250, 248, 0.6); + text-transform: uppercase; + margin-bottom: 1.5rem; + position: relative; + z-index: 1; +} + +.split-title { + font-family: var(--deepdrft-font-display); + font-size: clamp(2.5rem, 4vw, 3.8rem); + font-weight: 300; + color: var(--deepdrft-white); + line-height: 1.05; + margin-bottom: 1.5rem; + position: relative; + z-index: 1; +} + +.split-title em { + font-style: italic; + opacity: 0.65; +} + +.split-body { + font-family: var(--deepdrft-font-body); + font-size: 0.88rem; + line-height: 1.8; + color: rgba(250, 250, 248, 0.6); + max-width: 42ch; + position: relative; + z-index: 1; +} + +/* ── CTA BANNER (from Home.razor.css) ── */ +.cta-banner { + background: var(--deepdrft-navy); + padding: 6rem 3rem; + display: flex; + align-items: center; + justify-content: space-between; + gap: 3rem; + position: relative; + overflow: hidden; +} + +.cta-banner::before { + content: 'DRFT'; + position: absolute; + right: -2rem; + top: 50%; + transform: translateY(-50%); + font-family: var(--deepdrft-font-display); + font-size: 22rem; + font-weight: 300; + color: rgba(250, 250, 248, 0.03); + line-height: 1; + pointer-events: none; + user-select: none; + letter-spacing: -0.05em; +} + +.cta-text { + position: relative; + z-index: 1; +} + +.cta-headline { + font-family: var(--deepdrft-font-display); + font-size: clamp(2.5rem, 5vw, 5rem); + font-weight: 300; + color: var(--deepdrft-white); + line-height: 1; + margin-bottom: 1rem; +} + +.cta-headline em { + font-style: italic; + color: var(--deepdrft-green-accent); +} + +.cta-sub { + font-family: var(--deepdrft-font-body); + font-size: 0.88rem; + color: rgba(250, 250, 248, 0.4); + letter-spacing: 0.05em; +} + +.cta-actions { + display: flex; + gap: 1rem; + align-items: center; + position: relative; + z-index: 1; + flex-shrink: 0; + flex-wrap: wrap; +} + +.btn-white { + font-family: var(--deepdrft-font-mono); + font-size: 0.68rem; + letter-spacing: 0.2em; + text-transform: uppercase; + color: var(--deepdrft-navy); + background: var(--deepdrft-white); + border: none; + padding: 1rem 2.2rem; + cursor: pointer; + text-decoration: none; + transition: background 0.25s, color 0.25s; + display: inline-block; +} + +.btn-white:hover { + background: var(--deepdrft-green-accent); + color: var(--deepdrft-white); +} + +.btn-outline-white { + font-family: var(--deepdrft-font-mono); + font-size: 0.68rem; + letter-spacing: 0.2em; + text-transform: uppercase; + color: var(--deepdrft-white); + background: transparent; + border: 1px solid rgba(250, 250, 248, 0.3); + padding: 1rem 2.2rem; + cursor: pointer; + text-decoration: none; + transition: border-color 0.25s; + display: inline-block; +} + +.btn-outline-white:hover { border-color: var(--deepdrft-white); } + +@media (max-width: 599px) { + .cta-banner { + flex-direction: column; + align-items: flex-start; + gap: 2rem; + padding: 4rem 1.5rem; + } + + .cta-actions { + width: 100%; + } + + .btn-white, + .btn-outline-white { + flex: 1; + text-align: center; + min-width: 140px; + } + + .cta-banner::before { + font-size: 8rem; + right: -0.5rem; + } +} + +/* ── BIO CARDS (new — the only bespoke styling on About) ── + Assembled from the existing type tokens (display serif for the name, mono for + the role line, body for the bio), so they sit inside the established vocabulary + rather than inventing a new one. */ +.bio-card { + height: 100%; + background: var(--deepdrft-white); + border: 1px solid var(--deepdrft-border); + display: flex; + flex-direction: column; +} + +.bio-portrait { + width: 100%; + overflow: hidden; +} + +/* Graceful-degrade slot shown until a portrait file lands. A flat tonal panel in + the navy family with the site's aspect precedent (1365×2048 portrait). */ +.bio-portrait-placeholder { + width: 100%; + aspect-ratio: 1365 / 2048; + max-height: 60vh; + background: + linear-gradient(160deg, + color-mix(in srgb, var(--deepdrft-navy) 8%, var(--deepdrft-white)) 0%, + color-mix(in srgb, var(--deepdrft-navy) 16%, var(--deepdrft-white)) 100%); + border-bottom: 1px solid var(--deepdrft-border); +} + +.bio-meta { + padding: 2.25rem 2rem 2.5rem; +} + +.bio-name { + font-family: var(--deepdrft-font-display); + font-size: 2rem; + font-weight: 300; + line-height: 1.1; + color: var(--deepdrft-navy); + margin-bottom: 0.6rem; +} + +.bio-role { + font-family: var(--deepdrft-font-mono); + font-size: 0.6rem; + letter-spacing: 0.22em; + text-transform: uppercase; + color: var(--deepdrft-green-accent); + margin-bottom: 1.4rem; +} + +.bio-body { + font-family: var(--deepdrft-font-body); + font-size: 0.85rem; + line-height: 1.8; + color: var(--deepdrft-navy); + opacity: 0.7; +} + +@media (max-width: 960px) { + .section-dark-standfirst { font-size: 0.88rem; } +}