/* Card component */
-.card {
+/* =====================
+ Timeline Layout
+ ===================== */
+
+.timeline {
+ position: relative;
+ margin-left: auto;
+ margin-right: auto;
+ max-width: 64rem;
+ padding-left: 1rem;
+ padding-right: 1rem;
+ padding-top: 3rem;
+ padding-bottom: 3rem;
+}
+
+/* Vertical spine — center on desktop, left on mobile */
+
+.timeline::before {
+ content: '';
+ position: absolute;
+ top: 0px;
+ bottom: 0px;
+ left: 20px;
+ width: 2px;
+ background: linear-gradient(to bottom, var(--accent), var(--accent2, var(--accent)));
+ opacity: 0.7;
+}
+
+@media (min-width: 768px) {
+ .timeline::before {
+ left: 50%;
+ transform: translateX(-50%);
+ }
+}
+
+/* Each timeline row */
+
+.timeline-item {
+ position: relative;
+ margin-bottom: 2.5rem;
+ /* Mobile: offset right of left spine */
+ margin-left: 44px;
+}
+
+@media (min-width: 768px) {
+ .timeline-item {
+ margin-left: 0;
+ display: flex;
+ align-items: flex-start;
+ /* Each item takes full width; card is positioned via padding inside */
+ }
+}
+
+/* ---- Connector line ---- */
+
+.timeline-connector {
+ position: absolute;
+ top: 20px;
+ height: 2px;
+ /* Mobile: from spine (left:22px) to card left edge (left:44px) */
+ left: -22px;
+ width: 22px;
+}
+
+@media (min-width: 768px) {
+ /* Desktop: driven by .timeline-item--left / --right modifier */
+
+ .timeline-item--left .timeline-connector {
+ right: calc(50% - 28px + 1px);
+ left: auto;
+ width: 28px;
+ }
+
+ .timeline-item--right .timeline-connector {
+ left: calc(50% + 28px - 28px);
+ width: 28px;
+ }
+}
+
+/* ---- Node on spine ---- */
+
+.timeline-node {
+ position: absolute;
+ z-index: 10;
+ border-radius: 9999px;
+ top: 14px;
+ /* Mobile: on left spine at left:20px, node is 10px → left:15px */
+ left: -27px;
+ width: 10px;
+ height: 10px;
+ border: 2px solid var(--bg);
+}
+
+@media (min-width: 768px) {
+ .timeline-node {
+ width: 12px;
+ height: 12px;
+ top: 14px;
+ left: calc(50% - 6px);
+ /* Override mobile left positioning */
+ transform: none;
+ }
+
+ /* Reset mobile left for desktop — node always on center spine */
+
+ .timeline-item--left .timeline-node,
+ .timeline-item--right .timeline-node {
+ left: calc(50% - 6px);
+ }
+}
+
+/* ---- Card wrapper ---- */
+
+.timeline-card {
+ display: flex;
overflow: hidden;
border-radius: 0.5rem;
border-width: 1px;
- border-color: var(--border);
- transition-property: all;
- transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
- transition-duration: 200ms;
+ background-color: var(--surface);
}
-article.card.border-border\/30.rounded-lg.overflow-hidden.group.bg-bg {
+article.timeline-card.border-border\/30.rounded-lg.overflow-hidden.group.bg-bg {
border-color: var(--border);
box-shadow: 0 0 20px var(--accent-glow);
}
-article.border.border-border\/30.card.overflow-hidden.group.bg-bg {
+article.border.border-border\/30.timeline-card.overflow-hidden.group.bg-bg {
border-color: var(--border);
box-shadow: 0 0 20px var(--accent-glow);
}
-article.border.border-border\/30.rounded-lg.card.group.bg-bg {
+article.border.border-border\/30.rounded-lg.timeline-card.group.bg-bg {
border-color: var(--border);
box-shadow: 0 0 20px var(--accent-glow);
}
-.card {
- box-shadow: 0 0 20px var(--accent-glow);
+.timeline-card {
+ transition: box-shadow 0.2s, transform 0.2s;
}
-.card:hover {
+.timeline-card:hover {
transform: translateY(-2px);
- box-shadow: 0 0 30px var(--accent-glow);
}
-.card-image {
- aspect-ratio: 16 / 9;
+/* Mobile: full width */
+
+.timeline-card {
width: 100%;
- -o-object-fit: cover;
- object-fit: cover;
}
-.card-body > :not([hidden]) ~ :not([hidden]) {
- --tw-space-y-reverse: 0;
- margin-top: calc(0.75rem * calc(1 - var(--tw-space-y-reverse)));
- margin-bottom: calc(0.75rem * var(--tw-space-y-reverse));
+/* ---- Thumbnail panel ---- */
+
+.timeline-thumb {
+ flex-shrink: 0;
+ overflow: hidden;
}
-.card-body {
- padding: 1.25rem;
+article.border.border-border\/30.rounded-lg.timeline-thumb.group.bg-bg {
+ border-color: var(--border);
+ box-shadow: 0 0 20px var(--accent-glow);
+}
+
+.timeline-thumb {
+ /* Mobile: full width banner on top — handled by flex-direction:column on mobile card */
+ width: 100%;
+ height: 90px;
}
@media (min-width: 768px) {
- .card-body {
- padding: 1.5rem;
+ .timeline-thumb {
+ width: 38%;
+ height: auto;
+ aspect-ratio: 2 / 3;
}
}
-/* =====================
- Timeline Layout
- ===================== */
+.timeline-thumb img {
+ height: 100%;
+ width: 100%;
+ -o-object-fit: cover;
+ object-fit: cover;
+ transition: transform 0.2s;
+}
-/* Vertical spine — center on desktop, left on mobile */
+.timeline-card:hover .timeline-thumb img {
+ transform: scale(1.03);
+}
-/* Each timeline row */
+/* ---- Text panel ---- */
-/* ---- Connector line ---- */
+.timeline-body {
+ display: flex;
+ flex: 1 1 0%;
+ flex-direction: column;
+ gap: 0.5rem;
+ padding: 1rem;
+}
-/* ---- Node on spine ---- */
+/* Mobile card stacks thumbnail above body */
-/* ---- Card wrapper ---- */
+.timeline-card {
+ flex-direction: column;
+}
-/* Mobile: full width */
+@media (min-width: 768px) {
+ .timeline-card {
+ flex-direction: row;
+ }
-/* ---- Thumbnail panel ---- */
+ /* Left card: thumb first (outer=left), body second */
-/* ---- Text panel ---- */
+ .timeline-item--left .timeline-card {
+ flex-direction: row;
+ }
-/* Mobile card stacks thumbnail above body */
+ /* Right card: body first (inner=left), thumb last (outer=right) */
+
+ .timeline-item--right .timeline-card {
+ flex-direction: row-reverse;
+ }
+}
/* ---- Meta row (TYPE · date) ---- */
+.timeline-meta {
+ display: flex;
+ align-items: center;
+ gap: 0.5rem;
+ font-family: JetBrains Mono, monospace;
+ font-size: 0.75rem;
+ line-height: 1rem;
+ text-transform: uppercase;
+ letter-spacing: 0.1em;
+}
+
+.timeline-meta-sep {
+ color: var(--border);
+}
+
+.timeline-date {
+ text-transform: none;
+ letter-spacing: 0em;
+ color: var(--text-dim);
+}
+
/* ---- Title ---- */
+.timeline-title {
+ font-size: 1rem;
+ line-height: 1.5rem;
+ font-weight: 600;
+ line-height: 1.375;
+}
+
+.timeline-title a {
+ transition-property: color, background-color, border-color, text-decoration-color, fill, stroke;
+ transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
+ transition-duration: 150ms;
+}
+
+.timeline-title a:hover {
+ color: var(--accent);
+}
+
/* ---- Excerpt ---- */
+.timeline-excerpt {
+ overflow: hidden;
+ display: -webkit-box;
+ -webkit-box-orient: vertical;
+ -webkit-line-clamp: 3;
+ font-size: 0.875rem;
+ line-height: 1.25rem;
+ line-height: 1.625;
+ color: var(--text-dim);
+}
+
/* ---- Pinned badge ---- */
+.timeline-pinned {
+ display: inline-flex;
+ align-items: center;
+ gap: 0.25rem;
+ border-radius: 0.25rem;
+ padding-left: 0.5rem;
+ padding-right: 0.5rem;
+ padding-top: 0.125rem;
+ padding-bottom: 0.125rem;
+ font-size: 0.75rem;
+ line-height: 1rem;
+ font-weight: 600;
+}
+
/* ---- Type-color variants (node, connector, card) ---- */
/* Tech (purple) */
right: 0px;
}
-.right-3 {
- right: 0.75rem;
-}
-
.right-4 {
right: 1rem;
}
top: 0px;
}
-.top-3 {
- top: 0.75rem;
-}
-
.top-4 {
top: 1rem;
}
margin-top: 2rem;
}
-.line-clamp-1 {
- overflow: hidden;
- display: -webkit-box;
- -webkit-box-orient: vertical;
- -webkit-line-clamp: 1;
+.mt-auto {
+ margin-top: auto;
}
-.line-clamp-3 {
+.line-clamp-1 {
overflow: hidden;
display: -webkit-box;
-webkit-box-orient: vertical;
- -webkit-line-clamp: 3;
+ -webkit-line-clamp: 1;
}
.block {
max-width: 42rem;
}
-.max-w-3xl {
- max-width: 48rem;
-}
-
.max-w-4xl {
max-width: 56rem;
}
+.max-w-5xl {
+ max-width: 64rem;
+}
+
.max-w-7xl {
max-width: 80rem;
}
padding-right: 1.5rem;
}
-.py-0\.5 {
- padding-top: 0.125rem;
- padding-bottom: 0.125rem;
-}
-
.py-1 {
padding-top: 0.25rem;
padding-bottom: 0.25rem;
}
-.py-1\.5 {
- padding-top: 0.375rem;
- padding-bottom: 0.375rem;
-}
-
.py-12 {
padding-top: 3rem;
padding-bottom: 3rem;
color: var(--text);
}
-.group:hover .group-hover\:text-accent {
- color: var(--accent);
-}
-
@media (prefers-color-scheme: dark) {
.dark\:prose-invert {
--tw-prose-body: var(--tw-prose-invert-body);
opacity: 0.5;
}
-.group:hover .group-hover\:scale-105 {
- --tw-scale-x: 1.05;
- --tw-scale-y: 1.05;
- transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
-}
-
-.group:hover .group-hover\:text-accent {
- color: var(--accent);
-}
-
@media (min-width: 640px) {
.sm\:flex-row {
flex-direction: row;