feat: add route-backed project case studies
Some checks failed
Test and deploy / Verify production build (push) Has been cancelled
Test and deploy / Deploy production (push) Has been cancelled

This commit is contained in:
2026-09-09 22:00:57 +03:30
parent b3cfcfe057
commit 24cd86ede7
25 changed files with 1892 additions and 65 deletions

View File

@@ -0,0 +1,552 @@
.dialog {
position: fixed;
inset: 0;
width: 100vw;
max-width: none;
height: 100dvh;
max-height: none;
margin: 0;
padding: 0;
overflow: hidden;
border: 0;
background: transparent;
color: var(--text-primary);
}
.dialog::backdrop {
background: rgba(1, 13, 39, 0.52);
opacity: 0;
backdrop-filter: blur(3px);
transition: opacity 180ms var(--motion-ease-out);
}
.dialog[data-state='open']::backdrop {
opacity: 1;
}
.dialog[data-state='closing']::backdrop {
opacity: 0;
}
.sheet {
position: fixed;
right: 0;
bottom: 0;
left: 0;
display: flex;
flex-direction: column;
width: min(72rem, calc(100vw - 2rem));
height: min(86dvh, 56rem);
margin-inline: auto;
overflow: hidden;
border: 1px solid var(--border-strong);
border-bottom: 0;
border-radius: var(--radius-xl) var(--radius-xl) 0 0;
background: var(--bg-raised);
box-shadow: 0 -1rem 4rem rgba(1, 13, 39, 0.2);
transform: translateY(100%);
transition: transform 240ms cubic-bezier(0.32, 0.72, 0, 1);
will-change: transform;
}
.dialog[data-state='open'] .sheet {
transform: translateY(0);
}
.dialog[data-motion='none'] .sheet {
transition-duration: 0ms;
}
.utilityHeader {
position: relative;
z-index: 2;
display: grid;
flex: 0 0 auto;
grid-template-columns: 1fr auto 1fr;
align-items: center;
min-height: 4.5rem;
padding: 1rem var(--space-5) var(--space-3);
border-bottom: 1px solid var(--border-default);
background: color-mix(in srgb, var(--bg-raised) 94%, transparent);
}
.dragTarget {
position: absolute;
top: 0;
left: 50%;
display: flex;
align-items: center;
justify-content: center;
width: 8rem;
height: 2rem;
cursor: grab;
touch-action: none;
transform: translateX(-50%);
}
.dragTarget:active {
cursor: grabbing;
}
.dragHandle {
width: 2.75rem;
height: 0.25rem;
border-radius: var(--radius-pill);
background: var(--border-strong);
}
.drawerLabel {
grid-column: 2;
color: var(--text-muted);
font-size: var(--font-size-label-small);
font-weight: 700;
letter-spacing: var(--letter-spacing-eyebrow);
text-transform: uppercase;
}
.actions {
display: flex;
grid-column: 3;
gap: var(--space-2);
justify-self: end;
}
.actionButton,
.iconButton {
display: inline-flex;
align-items: center;
justify-content: center;
min-width: 2.75rem;
height: 2.75rem;
border: 1px solid var(--border-default);
border-radius: var(--radius-pill);
background: var(--bg-surface);
color: var(--text-primary);
cursor: pointer;
font: inherit;
font-size: var(--font-size-body-small);
font-weight: 650;
transition:
color var(--motion-duration-fast) ease,
background-color var(--motion-duration-fast) ease,
border-color var(--motion-duration-fast) ease,
transform var(--motion-duration-fast) var(--motion-ease-out);
}
.actionButton {
gap: var(--space-2);
padding-inline: var(--space-4);
}
.iconButton {
width: 2.75rem;
padding: 0;
}
.actionButton:active,
.iconButton:active,
.projectNavLink:active {
transform: scale(0.97);
}
.liveRegion {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border: 0;
}
.scrollArea {
flex: 1;
min-height: 0;
overflow-y: auto;
overscroll-behavior: contain;
scroll-padding-top: var(--space-5);
scrollbar-gutter: stable;
}
.content {
width: min(68rem, 100%);
margin-inline: auto;
padding: var(--space-8) var(--space-7) calc(var(--space-8) + env(safe-area-inset-bottom, 0px));
}
.hero {
max-width: 52rem;
margin-bottom: var(--space-8);
}
.date {
margin-bottom: var(--space-2);
color: var(--text-muted);
font-size: var(--font-size-label-small);
font-weight: 700;
letter-spacing: var(--letter-spacing-eyebrow);
text-transform: uppercase;
}
.title {
margin-bottom: var(--space-4);
color: var(--text-primary);
font-size: clamp(2rem, 5vw, 3.5rem);
font-weight: 780;
letter-spacing: -0.045em;
line-height: 1.05;
}
:global(html[dir='rtl']) .title,
:global(html[dir='rtl']) .date,
:global(html[dir='rtl']) .drawerLabel {
letter-spacing: 0;
}
.title:focus {
outline: none;
}
.title:focus-visible {
border-radius: var(--radius-sm);
outline: 3px solid var(--focus-ring);
outline-offset: var(--space-2);
}
.introduction {
max-width: 46rem;
color: var(--text-secondary);
font-size: var(--font-size-body-large);
line-height: var(--line-height-body-large);
}
.facts {
display: grid;
grid-template-columns: repeat(3, minmax(0, 1fr));
gap: var(--space-3);
margin-top: var(--space-6);
}
.facts > div {
padding: var(--space-4);
border: 1px solid var(--border-default);
border-radius: var(--radius-md);
background: var(--bg-surface);
}
.facts dt {
margin-bottom: var(--space-1);
color: var(--text-muted);
font-size: var(--font-size-label-small);
font-weight: 700;
text-transform: uppercase;
}
.facts dd {
color: var(--text-primary);
font-size: var(--font-size-body-small);
font-weight: 650;
line-height: var(--line-height-body-small);
}
.section {
margin-top: var(--space-8);
}
.sectionTitle {
margin-bottom: var(--space-4);
color: var(--text-primary);
font-size: var(--font-size-h3);
font-weight: 750;
line-height: var(--line-height-h3);
}
.section p,
.list {
color: var(--text-secondary);
font-size: var(--font-size-body-default);
line-height: var(--line-height-body-default);
}
.gallery {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: var(--space-4);
}
.featuredMedia {
grid-column: 1 / -1;
}
.imageFrame {
display: flex;
min-height: 10rem;
align-items: center;
justify-content: center;
overflow: hidden;
border: 1px solid var(--border-default);
border-radius: var(--radius-lg);
background: var(--color-blue-950);
}
.galleryImage {
display: block;
width: 100%;
height: auto;
object-fit: contain;
}
.gallery figcaption {
padding: var(--space-2) var(--space-1) 0;
color: var(--text-muted);
font-size: var(--font-size-body-small);
line-height: var(--line-height-body-small);
}
.storyGrid,
.stackGrid {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: var(--space-7);
}
.list {
display: grid;
gap: var(--space-3);
padding-inline-start: var(--space-5);
}
.list li::marker {
color: var(--accent-default);
}
.decisions {
display: grid;
grid-template-columns: repeat(3, minmax(0, 1fr));
gap: var(--space-3);
}
.decision {
padding: var(--space-5);
border: 1px solid var(--border-default);
border-radius: var(--radius-lg);
background: var(--bg-surface);
}
.decision > span {
display: inline-flex;
margin-bottom: var(--space-3);
padding: var(--space-1) var(--space-3);
border-radius: var(--radius-pill);
background: var(--bg-subtle);
color: var(--action-link);
font-size: var(--font-size-label-small);
font-weight: 700;
}
.decision h3 {
margin-bottom: var(--space-2);
color: var(--text-primary);
font-size: var(--font-size-body-default);
line-height: 1.4;
}
.decision p {
font-size: var(--font-size-body-small);
line-height: var(--line-height-body-small);
}
.metrics {
display: flex;
flex-wrap: wrap;
gap: var(--space-3);
margin-bottom: var(--space-5);
}
.metrics > div {
min-width: 9rem;
padding: var(--space-4);
border-radius: var(--radius-md);
background: var(--bg-subtle);
}
.metrics dt {
color: var(--text-primary);
font-size: var(--font-size-h3);
font-weight: 760;
}
.metrics dd {
color: var(--text-secondary);
font-size: var(--font-size-body-small);
}
.badges {
display: flex;
flex-wrap: wrap;
gap: var(--space-2);
}
.badges span {
padding: var(--space-2) var(--space-4);
border: 1px solid var(--border-default);
border-radius: var(--radius-pill);
background: var(--bg-surface);
color: var(--text-primary);
font-size: var(--font-size-body-small);
font-weight: 600;
}
.projectNavigation {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: var(--space-3);
margin-top: var(--space-9);
padding-top: var(--space-6);
border-top: 1px solid var(--border-default);
}
.projectNavLink {
display: flex;
min-height: 5rem;
align-items: center;
gap: var(--space-3);
padding: var(--space-4);
border: 1px solid var(--border-default);
border-radius: var(--radius-lg);
background: var(--bg-surface);
transition:
background-color var(--motion-duration-fast) ease,
border-color var(--motion-duration-fast) ease,
transform var(--motion-duration-fast) var(--motion-ease-out);
}
.projectNavLink svg {
flex: 0 0 auto;
width: var(--size-icon-md);
}
.projectNavLink span {
display: grid;
gap: var(--space-1);
}
.projectNavLink small {
color: var(--text-muted);
font-size: var(--font-size-label-small);
}
.projectNavLink strong {
color: var(--text-primary);
font-size: var(--font-size-body-default);
}
.nextProject {
justify-content: flex-end;
text-align: end;
}
@media (max-width: 1100px) {
.sheet {
width: calc(100vw - 1rem);
height: 90dvh;
}
.content {
padding-inline: var(--space-6);
}
.decisions {
grid-template-columns: 1fr;
}
}
@media (max-width: 650px) {
.sheet {
width: 100vw;
height: 92dvh;
}
.utilityHeader {
min-height: 4.25rem;
padding-inline: var(--space-4);
}
.drawerLabel {
justify-self: start;
}
.actionText {
position: absolute;
width: 1px;
height: 1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
}
.actionButton {
width: 2.75rem;
padding: 0;
}
.content {
padding: var(--space-7) var(--space-4) calc(var(--space-7) + env(safe-area-inset-bottom, 0px));
}
.hero,
.section {
margin-bottom: 0;
}
.title {
font-size: 2rem;
line-height: 1.15;
}
.introduction {
font-size: var(--font-size-body-default);
line-height: var(--line-height-body-default);
}
.facts,
.gallery,
.storyGrid,
.stackGrid,
.projectNavigation {
grid-template-columns: 1fr;
}
.featuredMedia {
grid-column: auto;
}
}
@media (hover: hover) and (pointer: fine) {
.actionButton:hover,
.iconButton:hover,
.projectNavLink:hover {
border-color: var(--accent-default);
background: var(--bg-subtle);
}
.projectNavLink:hover {
transform: translateY(-1px);
}
}
@media (prefers-reduced-motion: reduce) {
.sheet {
transform: translateY(0);
transition: opacity 120ms ease;
}
.dialog[data-state='opening'] .sheet,
.dialog[data-state='closing'] .sheet {
opacity: 0;
}
.dialog::backdrop {
transition-duration: 120ms;
}
}