]> danix's work - danix.xyz-2.git/commitdiff
fix: correct timeline layout bugs — desktop stacking, connector geometry, thumbnail...
authorDanilo M. <redacted>
Tue, 21 Apr 2026 09:57:12 +0000 (11:57 +0200)
committerDanilo M. <redacted>
Tue, 21 Apr 2026 09:57:12 +0000 (11:57 +0200)
- Remove flex from .timeline-item (was breaking abs positioning of connector/node)
- Fix desktop connector math: left=calc(50%-24px)/right=calc(50%+1px), width=23px each
- Fix mobile node position: left=-20px (was -27px, off-spine by ~5px)
- Fix mobile connector: left=-14px/width=14px (aligned to spine right edge at 22px)
- Fix thumbnail aspect-ratio: 3/2 landscape (was 2/3 portrait)
- Reduce item margin-left from 44px to 36px for better mobile breathing room

Co-Authored-By: Claude Haiku 4.5 <redacted>
themes/danix-xyz-hacker/assets/css/main.css
themes/danix-xyz-hacker/assets/css/main.min.css

index 89c3fda8b790583033ca4766a68e98740694b260..829cbcbc13537a72d5d0acfd47e9f08620bae7e5 100644 (file)
@@ -513,10 +513,11 @@ html.theme-light picture img[src="/images/default_thumbnail_dark.png"] {
     @apply relative mx-auto max-w-5xl px-4 py-12;
   }
 
-  /* Vertical spine — center on desktop, left on mobile */
+  /* Vertical spine */
   .timeline::before {
     content: '';
     @apply absolute top-0 bottom-0;
+    /* Mobile: fixed 20px from container left edge */
     left: 20px;
     width: 2px;
     background: linear-gradient(to bottom, var(--accent), var(--accent2, var(--accent)));
@@ -530,18 +531,16 @@ html.theme-light picture img[src="/images/default_thumbnail_dark.png"] {
     }
   }
 
-  /* Each timeline row */
+  /* Each timeline row — block, full width, positioned context for abs children */
   .timeline-item {
     @apply relative mb-10;
-    /* Mobile: offset right of left spine */
-    margin-left: 44px;
+    /* Mobile: push card right of the left spine (spine 20px + 2px + gap 8px = 30px; use 36px for breathing room) */
+    margin-left: 36px;
   }
 
   @screen md {
     .timeline-item {
       margin-left: 0;
-      @apply flex items-start;
-      /* Each item takes full width; card is positioned via padding inside */
     }
   }
 
@@ -550,21 +549,25 @@ html.theme-light picture img[src="/images/default_thumbnail_dark.png"] {
     @apply absolute;
     top: 20px;
     height: 2px;
-    /* Mobile: from spine (left:22px) to card left edge (left:44px) */
-    left: -22px;
-    width: 22px;
+    /* Mobile: spine right edge at 22px, item left at 36px → offset = -14px, width = 14px */
+    left: -14px;
+    width: 14px;
   }
 
   @screen md {
-    /* Desktop: driven by .timeline-item--left / --right modifier */
+    /*
+      spine center = 50% of item. Spine is 2px: left edge at 50%-1px, right at 50%+1px.
+      Cards occupy [0 .. 50%-24px] (left) or [50%+24px .. 100%] (right).
+      Left connector: left=50%-24px, width=23px → touches card right edge and spine left.
+      Right connector: left=50%+1px, width=23px → touches spine right and card left.
+    */
     .timeline-item--left .timeline-connector {
-      right: calc(50% - 28px + 1px);
-      left: auto;
-      width: 28px;
+      left: calc(50% - 24px);
+      width: 23px;
     }
     .timeline-item--right .timeline-connector {
-      left: calc(50% + 28px - 28px);
-      width: 28px;
+      left: calc(50% + 1px);
+      width: 23px;
     }
   }
 
@@ -572,8 +575,8 @@ html.theme-light picture img[src="/images/default_thumbnail_dark.png"] {
   .timeline-node {
     @apply absolute rounded-full z-10;
     top: 14px;
-    /* Mobile: on left spine at left:20px, node is 10px → left:15px */
-    left: -27px;
+    /* Mobile: spine center = 21px, item left = 36px → node left = 21-5-36 = -20px */
+    left: -20px;
     width: 10px;
     height: 10px;
     border: 2px solid var(--bg);
@@ -584,13 +587,7 @@ html.theme-light picture img[src="/images/default_thumbnail_dark.png"] {
       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 {
+      /* Desktop: spine center = 50% of item. Node center on spine: left = 50% - 6px */
       left: calc(50% - 6px);
     }
   }
@@ -598,6 +595,9 @@ html.theme-light picture img[src="/images/default_thumbnail_dark.png"] {
   /* ---- Card wrapper ---- */
   .timeline-card {
     @apply flex border rounded-lg overflow-hidden bg-surface;
+    /* Mobile: column (thumb on top) */
+    flex-direction: column;
+    width: 100%;
     transition: box-shadow 0.2s, transform 0.2s;
   }
 
@@ -605,34 +605,38 @@ html.theme-light picture img[src="/images/default_thumbnail_dark.png"] {
     transform: translateY(-2px);
   }
 
-  /* Mobile: full width */
-  .timeline-card {
-    width: 100%;
-  }
-
   @screen md {
-    /* Desktop: card occupies ~45% width, positioned by padding on .timeline-item */
+    /* Desktop: push card into left or right half via item padding */
     .timeline-item--left {
-      padding-right: calc(50% + 28px);
+      padding-right: calc(50% + 24px);
     }
     .timeline-item--right {
-      padding-left: calc(50% + 28px);
+      padding-left: calc(50% + 24px);
+    }
+    /* Left card: thumb outer-left, body inner-right */
+    .timeline-item--left .timeline-card {
+      flex-direction: row;
+    }
+    /* Right card: body inner-left, thumb outer-right */
+    .timeline-item--right .timeline-card {
+      flex-direction: row-reverse;
     }
   }
 
   /* ---- Thumbnail panel ---- */
   .timeline-thumb {
     @apply flex-shrink-0 overflow-hidden;
-    /* Mobile: full width banner on top — handled by flex-direction:column on mobile card */
+    /* Mobile: full-width banner */
     width: 100%;
     height: 90px;
   }
 
   @screen md {
     .timeline-thumb {
-      width: 38%;
+      /* 3:2 landscape: wider than tall */
+      width: 40%;
       height: auto;
-      aspect-ratio: 2 / 3;
+      aspect-ratio: 3 / 2;
     }
   }
 
@@ -650,25 +654,6 @@ html.theme-light picture img[src="/images/default_thumbnail_dark.png"] {
     @apply flex flex-col gap-2 p-4 flex-1;
   }
 
-  /* Mobile card stacks thumbnail above body */
-  .timeline-card {
-    flex-direction: column;
-  }
-
-  @screen md {
-    .timeline-card {
-      flex-direction: row;
-    }
-    /* Left card: thumb first (outer=left), body second */
-    .timeline-item--left .timeline-card {
-      flex-direction: row;
-    }
-    /* 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 {
     @apply flex items-center gap-2 text-xs font-mono tracking-widest uppercase;
index a64fb66fbbbb2e027890b42b80dde1a62a728c22..c330e5fc90f9c7a58bc90912513dce5d2fafcc4b 100644 (file)
@@ -1548,13 +1548,14 @@ button,
   padding-bottom: 3rem;
 }
 
-/* Vertical spine — center on desktop, left on mobile */
+/* Vertical spine */
 
 .timeline::before {
   content: '';
   position: absolute;
   top: 0px;
   bottom: 0px;
+  /* Mobile: fixed 20px from container left edge */
   left: 20px;
   width: 2px;
   background: linear-gradient(to bottom, var(--accent), var(--accent2, var(--accent)));
@@ -1568,21 +1569,18 @@ button,
   }
 }
 
-/* Each timeline row */
+/* Each timeline row — block, full width, positioned context for abs children */
 
 .timeline-item {
   position: relative;
   margin-bottom: 2.5rem;
-  /* Mobile: offset right of left spine */
-  margin-left: 44px;
+  /* Mobile: push card right of the left spine (spine 20px + 2px + gap 8px = 30px; use 36px for breathing room) */
+  margin-left: 36px;
 }
 
 @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 */
   }
 }
 
@@ -1592,23 +1590,27 @@ button,
   position: absolute;
   top: 20px;
   height: 2px;
-  /* Mobile: from spine (left:22px) to card left edge (left:44px) */
-  left: -22px;
-  width: 22px;
+  /* Mobile: spine right edge at 22px, item left at 36px → offset = -14px, width = 14px */
+  left: -14px;
+  width: 14px;
 }
 
 @media (min-width: 768px) {
-  /* Desktop: driven by .timeline-item--left / --right modifier */
+  /*
+      spine center = 50% of item. Spine is 2px: left edge at 50%-1px, right at 50%+1px.
+      Cards occupy [0 .. 50%-24px] (left) or [50%+24px .. 100%] (right).
+      Left connector: left=50%-24px, width=23px → touches card right edge and spine left.
+      Right connector: left=50%+1px, width=23px → touches spine right and card left.
+    */
 
   .timeline-item--left .timeline-connector {
-    right: calc(50% - 28px + 1px);
-    left: auto;
-    width: 28px;
+    left: calc(50% - 24px);
+    width: 23px;
   }
 
   .timeline-item--right .timeline-connector {
-    left: calc(50% + 28px - 28px);
-    width: 28px;
+    left: calc(50% + 1px);
+    width: 23px;
   }
 }
 
@@ -1619,8 +1621,8 @@ button,
   z-index: 10;
   border-radius: 9999px;
   top: 14px;
-  /* Mobile: on left spine at left:20px, node is 10px → left:15px */
-  left: -27px;
+  /* Mobile: spine center = 21px, item left = 36px → node left = 21-5-36 = -20px */
+  left: -20px;
   width: 10px;
   height: 10px;
   border: 2px solid var(--bg);
@@ -1631,15 +1633,7 @@ button,
     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 {
+    /* Desktop: spine center = 50% of item. Node center on spine: left = 50% - 6px */
     left: calc(50% - 6px);
   }
 }
@@ -1670,6 +1664,9 @@ article.border.border-border\/30.rounded-lg.timeline-card.group.bg-bg {
 }
 
 .timeline-card {
+  /* Mobile: column (thumb on top) */
+  flex-direction: column;
+  width: 100%;
   transition: box-shadow 0.2s, transform 0.2s;
 }
 
@@ -1677,10 +1674,28 @@ article.border.border-border\/30.rounded-lg.timeline-card.group.bg-bg {
   transform: translateY(-2px);
 }
 
-/* Mobile: full width */
+@media (min-width: 768px) {
+  /* Desktop: push card into left or right half via item padding */
 
-.timeline-card {
-  width: 100%;
+  .timeline-item--left {
+    padding-right: calc(50% + 24px);
+  }
+
+  .timeline-item--right {
+    padding-left: calc(50% + 24px);
+  }
+
+  /* Left card: thumb outer-left, body inner-right */
+
+  .timeline-item--left .timeline-card {
+    flex-direction: row;
+  }
+
+  /* Right card: body inner-left, thumb outer-right */
+
+  .timeline-item--right .timeline-card {
+    flex-direction: row-reverse;
+  }
 }
 
 /* ---- Thumbnail panel ---- */
@@ -1696,16 +1711,17 @@ article.border.border-border\/30.rounded-lg.timeline-thumb.group.bg-bg {
 }
 
 .timeline-thumb {
-  /* Mobile: full width banner on top — handled by flex-direction:column on mobile card */
+  /* Mobile: full-width banner */
   width: 100%;
   height: 90px;
 }
 
 @media (min-width: 768px) {
   .timeline-thumb {
-    width: 38%;
+    /* 3:2 landscape: wider than tall */
+    width: 40%;
     height: auto;
-    aspect-ratio: 2 / 3;
+    aspect-ratio: 3 / 2;
   }
 }
 
@@ -1731,30 +1747,6 @@ article.border.border-border\/30.rounded-lg.timeline-thumb.group.bg-bg {
   padding: 1rem;
 }
 
-/* Mobile card stacks thumbnail above body */
-
-.timeline-card {
-  flex-direction: column;
-}
-
-@media (min-width: 768px) {
-  .timeline-card {
-    flex-direction: row;
-  }
-
-  /* Left card: thumb first (outer=left), body second */
-
-  .timeline-item--left .timeline-card {
-    flex-direction: row;
-  }
-
-  /* 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 {