/* 
 * Project Build Reference CSS
 * Direct port from reference code for 100% parity
 * Phase 1: Static Structure and Styling
 */

/* ========================================
   Navigation Instructions
   ======================================== */
.navigation-instructions {
    position: fixed;
    top: var(--header-height);
    left: 0;
    width: 100%;
    height: var(--nav-instructions-height);
    background-color: var(--white);
    z-index: 200;
    display: flex;
    justify-content: space-between; /* Space between left and right columns */
    padding: 10px 30px; /* Add horizontal padding */
    border-bottom: 1px solid var(--light);
    transition: transform var(--transition-medium) ease;
}

.navigation-instructions.collapsed {
    transform: translateY(-100%);
}

/* Left column */
.nav-left-column {
    display: flex;
    gap: 48px; /* 48px spacing between entries */
    align-items: center;
}

/* Right column */
.nav-right-column {
    display: flex;
    gap: 48px; /* 48px spacing between entries */
    align-items: center;
    text-align: right;
}

.instruction-item {
    display: flex;
    gap: 10px;
    align-items: center;
    font-size: var(--font-size-small); /* 0.8rem */
    white-space: nowrap;
}

.instruction-label {
    color: var(--warm);
    text-transform: uppercase;
}

.instruction-value {
    font-weight: 700;
    color: var(--dark);
}

/* ========================================
   Grid Overlay - Visual Accent
   ======================================== */
.grid-overlay {
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    pointer-events: none;
    opacity: 0.05;
    z-index: 100;
}

.grid-overlay .grid-line {
    position: absolute;
    background-color: var(--dark);
}

.grid-overlay .grid-line.horizontal {
    height: 1px;
    width: 100%;
}

.grid-overlay .grid-line.horizontal:nth-child(1) {
    top: 25%;
}

.grid-overlay .grid-line.horizontal:nth-child(2) {
    top: 50%;
}

.grid-overlay .grid-line.horizontal:nth-child(3) {
    top: 75%;
}

.grid-overlay .grid-line.vertical {
    width: 1px;
    height: 100%;
}

.grid-overlay .grid-line.vertical:nth-child(4) {
    left: 20%;
}

.grid-overlay .grid-line.vertical:nth-child(5) {
    left: 40%;
}

.grid-overlay .grid-line.vertical:nth-child(6) {
    left: 60%;
}

.grid-overlay .grid-line.vertical:nth-child(7) {
    left: 80%;
}

/* ========================================
   Scanner Line
   ======================================== */
.scanner-line {
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
    height: 2px;
    background: linear-gradient(90deg, 
        var(--cyan) 0%, 
        var(--blue) 20%, 
        var(--purple) 40%, 
        var(--pink) 60%, 
        var(--darkblue) 80%, 
        var(--cyan) 100%);
    background-size: 200% 100%;
    opacity: 0;
    z-index: 150;
    pointer-events: none;
}

.scanner-line.animate {
    animation: 
        scanner-move 3s ease-in-out,
        gradient-shift 3s linear,
        scanner-opacity 3s ease-in-out;
}

@keyframes scanner-move {
    0% { top: 0; }
    100% { top: 100%; }
}

@keyframes gradient-shift {
    0% { background-position: 0% 50%; }
    100% { background-position: 200% 50%; }
}

@keyframes scanner-opacity {
    0%, 100% { opacity: 0; }
    20%, 80% { opacity: 0.7; }
}

/* ========================================
   Projects Container
   ======================================== */
.projects-container {
    display: flex;
    margin-top: calc(var(--header-height) + var(--nav-instructions-height));
    height: calc(100vh - var(--header-height) - var(--nav-instructions-height) - var(--footer-height));
    width: 96%; /* Aligns with header's bottom border width */
    margin-left: 2%; /* Creates indentation matching header */
    margin-right: 2%; /* Creates indentation matching header */
}

/* ========================================
   Project Columns - Base Structure
   ======================================== */
.project-column {
    flex: 0.8; /* Reduced from 1 for narrower collapsed columns */
    height: 100%;
    position: relative;
    transition: flex 0.45s cubic-bezier(0.22, 1, 0.36, 1), 
                background-color 0.4s ease,
                z-index 0s linear;
    overflow: hidden;
    cursor: pointer;
    background-color: var(--light);
    pointer-events: auto;
    /* Angled borders inspired by footer */
    clip-path: polygon(2% 0, 98% 0, 100% 100%, 0% 100%);
    margin: 0 2px;
    /* Chrome optimization - only use will-change on hover/active */
    contain: layout style;
    /* Force GPU acceleration in Chrome */
    -webkit-backface-visibility: hidden;
    backface-visibility: hidden;
    -webkit-perspective: 1000;
    perspective: 1000;
}

.project-column:first-child {
    margin-left: 0;
}

.project-column:last-child {
    margin-right: 0;
}

/* Intermediate hover state - visual feedback only */
.project-column:hover:not(.active) {
    flex: 0.96; /* 20% more than 0.8 */
    background-color: var(--lightest);
    transform: translateZ(0);
    -webkit-transform: translateZ(0); /* Chrome optimization */
    position: relative;
    z-index: 5; /* Above normal columns but below active */
    will-change: flex, transform; /* Only add during interaction */
}

/* Full active state - JavaScript controlled */
.project-column.active {
    flex: 7; /* Full expansion */
    background-color: var(--white) !important;
    transform: translateZ(0);
    -webkit-transform: translateZ(0); /* Chrome optimization */
    overflow: visible; /* Ensure content is visible */
    position: relative; /* Ensure proper stacking context */
    z-index: 10; /* Ensure active column is above others during transition */
    will-change: flex, transform; /* Only add during interaction */
}

/* ========================================
   Project Collapsed View
   ======================================== */
.project-collapsed {
    position: relative;
    width: 100%;
    height: 100%;
    display: flex;
    flex-direction: column;
    justify-content: space-between;
    padding: 30px 1px;
    transition: opacity 0.35s cubic-bezier(0.22, 1, 0.36, 1);
    will-change: opacity;
}

.project-collapsed .coords-system {
    width: 84%;
    height: 100px;
    position: relative;
    margin: 0 auto; /* Center horizontally within collapsed column */
}

.project-collapsed .project-number {
    position: absolute;
    top: 15px;
    left: 15px;
    font-size: var(--font-size-super-huge);
    font-weight: 900;
    font-family: var(--font-primary);
    line-height: 0.9;
    z-index: 5;
    transition: color var(--transition-medium) ease, opacity var(--transition-medium) ease;
    color: var(--dark);
    opacity: 0.72;
}

/* START CLEAN-FIX-P5-S6.5-PROJECT-NUMBER-PAD-CONDITIONAL
   Conditional leading-zero display for P2-P5 collapsed-state project numbers.

   Design intent (user-specified 2026-04-14):
   - When ALL project columns are in default-collapsed state (no .active
     sibling), show leading-zero 2-char format: "01", "02", "03", "04"
     for P2-P5. Gives the design-system feel of a coordinate table at rest.
   - When ONE project column is .active and the others are in subsidiary
     collapsed state, show single-digit 1-char format: "1", "2", "3", "4".
     The collapsed subsidiary columns are too narrow (~70px) to legibly
     render 2 characters at 72px bold — "01" truncates/overlaps with
     sibling coord-system elements (user-reported in image #34).

   Implementation: The HTML emits the leading zero wrapped in
   <span class="num-pad">0</span> inside .project-number. This CSS rule
   hides .num-pad ONLY when an active project exists in .projects-container.

   Selector: .projects-container:has(.project-column.active) — the :has()
   pseudo-class detects if any descendant .project-column has the .active
   class. When true, all .num-pad spans inside subsidiary (non-active)
   project columns are hidden via display: none.

   Cascade / fallback: If :has() is unsupported (very old browsers), the
   .num-pad will always show, which is the "d.c state" fallback — leading
   zero visible everywhere. Graceful degradation — no layout break.

   P1/P6 exclusion: P1 uses "™" symbol and P6 uses "º" symbol (not digit
   characters), so they have no .num-pad spans. The rule is naturally
   scoped to P2-P5 where .num-pad exists.

   Evidence: User-reported issue 2026-04-14 (image #34): collapsed
   subsidiary project columns showing clipped "0:", "02", "03", "04"
   numbers with P1 active. Requested single-digit display when collapsed
   and another column is expanded.

   To revert: Search CLEAN-FIX-P5-S6.5-PROJECT-NUMBER-PAD-CONDITIONAL,
   delete everything between START and END markers. Then also remove
   <span class="num-pad">0</span> wrappers in index.html at the 4
   P2-P5 .project-number divs (marked with
   CLEAN-FIX-P5-S6.5-PROJECT-NUMBER-PADDING comments). */
.projects-container:has(.project-column.active) .project-column:not(.active) .num-pad {
    display: none;
}
/* END CLEAN-FIX-P5-S6.5-PROJECT-NUMBER-PAD-CONDITIONAL */

.project-collapsed .accent-color {
    opacity: 0.6;
}

/* Full opacity for expanded state accent colors */
.project-column.active .accent-color {
    opacity: 1;
}

.project-collapsed .project-title-container {
    position: absolute;
    bottom: 45px;
    left: 15px;
    right: 15px;
    text-align: left;
}

.project-collapsed .project-title {
    font-size: var(--font-size-huge);
    font-weight: 800;
    text-transform: uppercase;
    font-family: var(--font-primary);
    letter-spacing: -0.02em;
    transition: color var(--transition-medium) ease;
    color: var(--dark);
}



/* Full opacity for expanded state elements */
.project-column.active * {
    opacity: 1;
}

/* Ensure collapsed view is properly visible in default state */
.project-column:not(.active) .project-collapsed {
    opacity: 1;
    pointer-events: auto;
}

/* Ensure the two-column layout in expanded view */
.project-expanded .project-info-column,
.project-expanded .mockups-column {
    height: 100%;
    position: relative;
}

/* ========================================
   Coordinate System
   ======================================== */
.coords-system {
    position: relative;
    width: 100%;
    height: 100%;
}

.coord-point {
    position: absolute;
    width: 6px;
    height: 6px;
    background-color: currentColor;
    border-radius: 50%;
    top: -3px;  /* Center on coord-line intersection (0 - 3px) */
    left: 0;    /* Center on coord-line intersection (3px - 3px) */
    z-index: 2;
}

.project-collapsed .coord-point {
    opacity: 0.5;
}

/* Full opacity for expanded state */
.project-column.active .coord-point {
    opacity: 1;
}

.coord-line {
    position: absolute;
    background-color: var(--dark) !important;
    transition: all var(--transition-medium) ease;
}

.project-collapsed .coord-line {
    opacity: 0.5;
}

/* Full opacity for expanded state coord-lines */
.project-column.active .coord-line {
    opacity: 1;
}

.coord-line.x {
    top: 3px;
    left: 6px;
    height: 1px;
    width: calc(100% - 6px);
}

.coord-line.y {
    top: 0;
    left: 3px;
    width: 1px;
    height: calc(100% - 0px);
}

/* Accessing state for expanded view */
.coords-system.accessing .coord-point {
    background-color: var(--dark);
    opacity: 1;
    animation: coordPulse 2s ease-in-out infinite;
}

.coords-system.accessing .coord-line {
    background-color: var(--dark);
}

/* Coordinate pulse animation */
@keyframes coordPulse {
    0%, 100% {
        transform: scale(1);
        opacity: 1;
    }
    50% {
        transform: scale(1.5);
        opacity: 0.6;
    }
}

/* ========================================
   Project Specific Colors & Backgrounds
   ======================================== */
/* Project 1 - Warm accent color (NOT background) */
#project1 .accent-color {
    color: var(--warm);
}

/* All project columns have light background in collapsed state */
/* Lightest background on hover, white on active */
#project1:hover:not(.active) {
    background-color: var(--lightest);
}

#project1.active {
    background-color: var(--white);
}

/* Additional project-specific coord point colors */
#project1 .coords-system .coord-point {
    background-color: var(--warm) !important;
}

/* Removed - coord-lines should be dark in expanded state */

/* Project-specific accent colors (NOT for title) */
#project1 .accent-color,
#project1 .title-accent {
    color: var(--warm);
}

/* Project 2 - Blue */
#project2 .coords-system .coord-point {
    background-color: var(--blue) !important;
}

/* Removed - coord-lines should be dark in expanded state */

#project2 .accent-color,
#project2 .title-accent {
    color: var(--blue);
}

/* Project 3 - Magenta */
#project3 .coords-system .coord-point {
    background-color: var(--pink) !important;
}

/* Removed - coord-lines should be dark in expanded state */

#project3 .accent-color,
#project3 .title-accent {
    color: var(--pink);
}

/* Project 4 - Purple */
#project4 .coords-system .coord-point {
    background-color: var(--purple) !important;
}

/* Removed - coord-lines should be dark in expanded state */

#project4 .accent-color,
#project4 .title-accent {
    color: var(--purple);
}

/* Project 5 - Darkblue */
#project5 .coords-system .coord-point {
    background-color: var(--darkblue) !important;
}

/* Removed - coord-lines should be dark in expanded state */

#project5 .accent-color,
#project5 .title-accent {
    color: var(--darkblue);
}

/* Project 6 - Cyan */
#project6 .coords-system .coord-point {
    background-color: var(--cyan) !important;
}

/* Removed - coord-lines should be dark in expanded state */

#project6 .accent-color,
#project6 .title-accent {
    color: var(--cyan);
}

/* ========================================
   PROJECT-SPECIFIC BORDER COLORS
   ======================================== */
/* Project-specific accent colors for subtitle and impact */
#project1 .project-subtitle {
    border-top-color: var(--warm);
}
#project1 .project-impact {
    border-left-color: var(--warm);
}

#project2 .project-subtitle {
    border-top-color: var(--blue);
}
#project2 .project-impact {
    border-left-color: var(--blue);
}

#project3 .project-subtitle {
    border-top-color: var(--pink);
}
#project3 .project-impact {
    border-left-color: var(--pink);
}

#project4 .project-subtitle {
    border-top-color: var(--purple);
}
#project4 .project-impact {
    border-left-color: var(--purple);
}

#project5 .project-subtitle {
    border-top-color: var(--darkblue);
}
#project5 .project-impact {
    border-left-color: var(--darkblue);
}

#project6 .project-subtitle {
    border-top-color: var(--cyan);
}
#project6 .project-impact {
    border-left-color: var(--cyan);
}

/* ========================================
   Cube Animation Styles
   ======================================== */
.cube-wrapper {
    display: inline-block;
    width: auto;
    height: 20px;
    position: relative;
    perspective: 1000px;
    margin: 0 8px;
}

.cube {
    width: 100%;
    height: 100%;
    position: relative;
    transform-style: preserve-3d;
    -webkit-transform-style: preserve-3d; /* Chrome/Safari */
    transition: transform 0.6s ease;
    -webkit-backface-visibility: hidden;
    backface-visibility: hidden;
}

.cube-face {
    position: absolute;
    width: 100%;
    height: 100%;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: var(--font-size-standard); /* 0.9rem */
    font-weight: 600;
    background-color: var(--white);
    /*border: 1px solid var(--light);*/
    backface-visibility: hidden;
    padding: 0 12px;
    white-space: nowrap;
}

.cube-face.front {
    transform: translateZ(10px);
}

.cube-face.back {
    transform: rotateX(180deg) translateZ(10px);
}

.cube-face.top {
    transform: rotateX(90deg) translateZ(10px);
}

.cube-face.bottom {
    transform: rotateX(-90deg) translateZ(10px);
}

.cube-face.left {
    transform: rotateY(-90deg) translateZ(10px);
}

.cube-face.right {
    transform: rotateY(90deg) translateZ(10px);
}

/* Cube rotation on hover */
.overview-trigger:hover .cube,
.view-case-btn:hover .cube {
    transform: rotateX(180deg);
}

/* ========================================
   Module Indicators
   ======================================== */
.module-indicator {
    position: relative;
    width: 16px;
    height: 16px;
    border: 2px solid var(--dark);
    border-radius: 50%;
    display: inline-block;
}

.pulse-ring {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    width: 100%;
    height: 100%;
    border: 2px solid var(--dark);
    border-radius: 50%;
    opacity: 0;
}

.pulse-ring.animate {
    animation: pulse 2s ease-out infinite;
}

@keyframes pulse {
    0% {
        width: 100%;
        height: 100%;
        opacity: 1;
    }
    100% {
        width: 200%;
        height: 200%;
        opacity: 0;
    }
}



.project-subtitle {
    font-family: var(--font-secondary); /* Helvetica Neue for consistency */
    font-size: var(--font-size-standard); /* Same size as impact */
    font-weight: 600; /* Slightly heavier for hierarchy */
    line-height: 1.4;
    margin: 0; /* Reset margin - using container gap */
    color: var(--black); /* Darker for emphasis */
    padding-top: 6px; /* Space for top accent - 6n compliant */
    border-top: 1px solid var(--dark); /* Default, will be overridden per project */
    position: relative;
}

.project-impact {
    font-family: var(--font-secondary); /* Helvetica Neue */
    font-size: var(--font-size-standard);
    font-weight: 500;
    color: var(--dark);
    border-left: 6px solid var(--dark); /* 6n compliant border width */
    padding-left: 18px; /* 6n compliant padding */
    margin: 0; /* Reset margin - using container gap */
    line-height: 1.5;
}

.project-impact .highlight {
    font-weight: 700;
    color: var(--black); /* Default to black for better contrast */
}

/* ========================================
   Overview Section
   ======================================== */
/* Styles consolidated to OVERVIEW TRIGGER section below */

/* ========================================
   Work Categories
   ======================================== */
/* Styles moved to expanded view section (line 1087) */

/* ========================================
   CTA Buttons
   ======================================== */
/* Styles moved to expanded view section below */

/* ========================================
   Mockups Column Base Styles
   ======================================== */
.mockups-column {
    /* START CLEAN-FIX-P5-S5C-CLAMP */
    /* Smooth scaling replaces the hard 350px switch at LG (see @media below, now removed).
       clamp(360px, 50%, 960px):
         - Min 360px (60×6n) — safety floor at narrow parent widths (820px desktop entry)
         - Preferred 50% — matches legacy XL behavior for familiar layout proportions
         - Max 960px (160×6n) — prevents mockups from dominating at XL wide (1920×1080)
       At 820-991px: 50% of parent (~390-475px) flows smoothly
       At 992-1199px: 50% (~475-575px) replaces the old hardcoded 350px jump
       At 1200px+: 50% (~576-920px) grows up to 960px ceiling
       To revert: Change back to `width: 50%;` and restore @media (max-width: 1199px) override */
    width: clamp(360px, 50%, 960px);
    /* END CLEAN-FIX-P5-S5C-CLAMP */
    flex: 1;
    /* background-color: var(--lightest);
    border-left: 1px solid var(--light); */
    display: flex;
    flex-direction: column;
    height: 100%;
    position: relative;
}

/* ========================================
   Hide collapsed view when expanded
   ======================================== */
.project-column.active .project-collapsed {
    opacity: 0;
    pointer-events: none;
}

/* ========================================
   Responsive Considerations
   ======================================== */
/* START CLEAN-FIX-PHASE8-BREAKPOINT-COLUMNS */
/* LG Breakpoint - Large Laptops/Small Desktops */
/* START CLEAN-FIX-P5-S5C-CLAMP */
/* Hard 350px width switch at LG removed — replaced by clamp(360px, 50%, 960px) in base .mockups-column rule.
   Old rule caused visible layout jump between 1199px (350px hardcoded) → 1200px (50% = ~576px).
   To revert: Uncomment the block below AND restore `width: 50%;` in base rule */
/*
@media (max-width: 1199px) {
    .mockups-column {
        width: 350px;
    }
}
*/
/* END CLEAN-FIX-P5-S5C-CLAMP */

/* SM Breakpoint - Large Phones/Small Tablets */
@media (max-width: 767px) {
    .projects-container {
        flex-direction: column;
        height: auto;
        margin-top: var(--header-height);
    }

    .project-column {
        flex: none;
        height: 100vh;
        clip-path: none;
        margin: 0;
    }

    .navigation-instructions {
        display: none;
    }
}
/* END CLEAN-FIX-PHASE8-BREAKPOINT-COLUMNS */

/* ========================================
   EXPANDED VIEW - CORE LAYOUT
   ======================================== */

/* Project Expanded View - Two-Column Layout with opacity transitions */
/* START CLEAN-FIX-P5-S7C2-CONTENT-FADE-SYNC
   Smooth content fade on expand/collapse using @starting-style +
   transition-behavior: allow-discrete (2026-04-15 user visual call).

   Problem: the `transition: opacity 0.35s` on this rule NEVER FIRED.
   Classic CSS limitation — when an element goes from `display: none`
   to `display: flex`, the browser re-enters the element into the
   render tree with the NEW computed value (opacity: 1 via the
   .project-column.active rule at line ~1345). There's no "before"
   state to transition from, so the opacity change is instant.

   For P2-P5 this was imperceptible because the content is relatively
   light — the content appearing all at once at opacity 1 reads as
   "fast expand" rather than as a flash. For P1 (heavy content: 25+
   skill tags, Designer Overview with process sections) and P6 (similar
   curation density), the instant render is visibly jerky — user
   reported the symptom as "P1 flashes content THEN begins to expand"
   during M1 momentum flex verification (2026-04-15).

   Fix: modern CSS @starting-style + transition-behavior: allow-discrete.

   (1) `transition: display 0.45s allow-discrete` added to the
       transition list. The `allow-discrete` transition-behavior lets
       display participate in transitions — it flips to the visible
       value at the START of an incoming transition and flips to
       `none` at the END of an outgoing transition.

   (2) `@starting-style { opacity: 0 }` added to the
       `.project-column.active .project-expanded` rule (line ~1345).
       Declares the starting value when the element first transitions
       into the matching state. Browser now has an explicit "before"
       value (0) distinct from the "after" value (1), so the opacity
       transition can interpolate over the 0.45s duration.

   Browser support (as of April 2026):
   - @starting-style: Chrome 117+ (Aug 2023), Firefox 129+ (Aug 2024),
     Safari 17.5+ (May 2024)
   - transition-behavior: allow-discrete: Chrome 117+, Firefox 129+,
     Safari 17.4+
   All shipped before this commit date. Fallback consideration: older
   browsers (pre-support) would see the OLD behavior (instant render,
   no fade), which is what the code did for years before this fix.
   No regression, graceful degradation.

   Duration choice (0.45s):
   Matches the base `.project-column` flex transition duration at
   820+ (CLEAN-FIX-P5-S7C2-COLUMN-TRANSITION-SMOOTHING commit 4ea0cc0).
   At XL the flex transition extends to 0.55s via M1 (49a08bb) — the
   0.1s difference is acceptable (content finishes fading at 82% of
   flex expansion; still reads as synchronized). Keeping opacity at
   0.45s for all breakpoints avoids the complexity of a media override
   on .project-expanded and stays within the "fade finishes before or
   at same time as column expansion" rule of thumb.

   Scope: all desktop breakpoints (820+) since the mobile override at
   v3-project-columns-responsive.css:495 forces `.project-expanded
   { display: none }` at max-width: 819px — my new transition declaration
   stays in effect but mobile never activates display: flex anyway, so
   the fix is effectively desktop-scoped without needing a media query.

   V6 border-top/bottom side effect: V6 renders on .project-expanded as
   rectangle borders. During the 0.45s fade-in, the borders fade in
   alongside the content (same element, same opacity). During fade-out
   (collapse), borders fade out in sync. Visually harmonious.

   Dependencies: CLEAN-FIX-P5-S7C2-COLUMN-TRANSITION-SMOOTHING (4ea0cc0)
   for the smooth clip-path morphing. This commit adds the parallel
   smooth content fade, completing the "smooth expand/collapse across
   all projects at all desktop screen sizes" user goal.

   Reversibility: Search CLEAN-FIX-P5-S7C2-CONTENT-FADE-SYNC and delete
   everything between START and END markers. Two blocks — the base rule
   transition update here and the @starting-style addition inside the
   .project-column.active .project-expanded rule below. Full `git revert
   <sha>` clean. */
.project-expanded {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    display: none; /* Initially hidden, will be shown by JS */
    opacity: 0; /* Start with opacity 0 */
    transition: opacity 0.45s cubic-bezier(0.22, 1, 0.36, 1),
                display 0.45s allow-discrete;
    will-change: opacity;
    flex-direction: row; /* Ensure horizontal layout */
    z-index: 10;
    background-color: var(--white);
}
/* END CLEAN-FIX-P5-S7C2-CONTENT-FADE-SYNC — paired with @starting-style
   block inside .project-column.active .project-expanded rule below */

/* Ensure the two-column layout in expanded view */
.project-expanded .project-info-column,
.project-expanded .mockups-column {
    height: 100%;
    position: relative;
}

/* Project Info Column Styles */
.project-info-column {
    flex: 1;
    width: 50%;
    padding: 42px 18px; /* 7×6n vertical, 3×6n horizontal */
    overflow: visible; /* Changed from hidden to allow overlay to show properly */
    display: flex;
    flex-direction: column;
    justify-content: space-between;
    gap: 36px; /* 6n compliant gap between flex items */
    height: 100%;
    position: relative; /* Needed for absolute positioned overlay */
    box-sizing: border-box;
}

/* START CLEAN-FIX-P5-S4A-VERTICAL-FIT */
/* Tiered padding compression for shorter viewports
   Ensures 6 flex children (header, subtitle, timeline, categories, overview-trigger, module) fit
   To revert: Delete between START/END markers */

/* Tier 1: Moderate compression (≤900px height = 150×6n) — covers XL min (1200×800), LG max (1199×800) */
@media (max-height: 900px) {
    .project-info-column {
        padding: 30px 18px; /* 5×6n vertical, 3×6n horizontal */
        gap: 24px; /* 4×6n — reduced from 36px */
    }
}

/* Tier 2: Aggressive compression (≤720px height = 120×6n) — covers LG min (992×700) */
@media (max-height: 720px) {
    .project-info-column {
        padding: 24px 18px; /* 4×6n vertical, 3×6n horizontal */
        gap: 18px; /* 3×6n — tightest comfortable gap */
    }
}
/* END CLEAN-FIX-P5-S4A-VERTICAL-FIT */

/* START G8G9R8-FIX6: Removed blanket flex-shrink: 0
   Was: flex-shrink: 0; on all children — prevented module from fitting in viewport
   Middle items (subtitle, timeline, work-categories, overview-trigger) can now compress if needed
   Header and module get targeted flex-shrink: 0 at their own selectors (.project-header, .project-module)
   To revert: Add flex-shrink: 0; back to this rule, remove it from .project-header and .project-module
   END G8G9R8-FIX6 */
/* Default spacing for direct children of project-info-column */
.project-info-column > * {
    transition: margin 0.35s cubic-bezier(0.22, 1, 0.36, 1);
    margin: 0; /* Reset margins - using flexbox gap instead */
}


/* Set the order of components in project-info-column */
.project-header {
    order: 1;
    flex-shrink: 0;  /* G8G9R8-FIX6: Header must never shrink */
}

.project-subtitle-container {
    order: 2;
    /* Visual container styling */
    background-color: rgba(48, 51, 51, 0.03); /* Very subtle dark background */
    clip-path: polygon(1% 0, 100% 0, 100% 100%, 0% 100%); /* Angular left edge, vertical right edge */
    padding: 18px;
    display: flex;
    flex-direction: column;
    gap: 12px; /* 6n compliant spacing between subtitle and impact */
    position: relative;
    transition: background-color var(--transition-fast) ease;
    /* START CLEAN-FIX-P5-S7A-V3-SUBTITLE-SHADOW
       Accent shadow on subtitle container. --accent-rgb cascades from #projectN root.
       To revert: Delete this box-shadow declaration between START/END markers. */
    box-shadow: 0 0 18px rgba(var(--accent-rgb, 121, 126, 128), 0.25);
    /* END CLEAN-FIX-P5-S7A-V3-SUBTITLE-SHADOW */
}

/* Subtle hover effect on container */
.project-column.active .project-subtitle-container:hover {
    background-color: rgba(48, 51, 51, 0.05); /* Slightly darker on hover */
}

.project-timeline-horizontal {
    order: 3;
    width: 100%;
    position: relative;
}

/* Timeline start and end labels */
.project-timeline-horizontal .timeline-start,
.project-timeline-horizontal .timeline-end {
    font-size: var(--font-size-small);
    font-weight: 600;
    color: var(--dark);
    font-family: var(--font-primary);
}

.project-timeline-horizontal .timeline-start {
    position: absolute;
    left: 0;
    top: -20px;
}

.project-timeline-horizontal .timeline-end {
    position: absolute;
    right: 0;
    top: -20px;
}

/* Timeline track */
.project-timeline-horizontal .timeline-track {
    width: 100%;
    height: 2px;
    background-color: var(--light);
    position: relative;
    margin: 30px 0 15px 0;
}

/* Timeline markers - Base styles only */
.project-timeline-horizontal .timeline-marker {
    position: absolute;
    top: 0;
    transform: translate(-50%, -50%);
}
/* Note: Each project timeline has its own custom marker implementation */

.work-categories {
    order: 4;
}

.overview-trigger {
    order: 5;
}

.project-overview {
    order: 5;
}

.case-study-cta {
    order: 5; /* Same as overview-trigger to maintain relative position */
    display: none !important; /* Force hide with !important */
}

/* Only show case-study-cta for project1 */
#project1 .case-study-cta {
    display: block !important; /* Force show with !important */
}

/* CLEAN-FIX-P5-S6.5c-IV5-CASE-STUDY-CTA-P1-ONLY-CLEANUP 2026-05-01:
   Removed `#project2..6 .case-study-cta { display: none !important }` rule.
   Reason: case-study-cta is P1-only by design — only P1 has the markup at
   index.html:223. P4 + P5 had dead markup (removed in this same chunk);
   P2/P3/P6 never had markup, so those selectors were defensive against
   re-introduction that never occurred + are genuinely unused. Removing
   the entire rule drops `!important` count 19 → 18 in project-column-
   styles.css. Net behavior delta: ZERO (no rendered elements affected).
   To revert: restore the `#project2..6 .case-study-cta { display: none
   !important }` rule + restore the P4 + P5 markup blocks at index.html
   (search CLEAN-FIX-P5-S6.5c-IV5-CASE-STUDY-CTA-P1-ONLY-CLEANUP). */

.project-module {
    order: 6;
    flex-shrink: 0;  /* G8G9R8-FIX6: Module must never shrink — always visible at bottom */
    /* Removed margin-top: auto - using flexbox gap for spacing */
}

/* ========================================
   CASE STUDY CTA BUTTON
   ======================================== */

/* Case study CTA container - using grid gap for spacing */

/* View case button - Light theme from reference */
.view-case-btn {
    display: flex;
    align-items: center;
    background-color: var(--light);
    padding: 15px 20px;
    border: none;
    cursor: pointer;
    position: relative;
    transition: background-color var(--transition-fast) ease;
    width: 100%;
    color: var(--dark);
}

.view-case-btn:hover {
    background-color: var(--cool);
    color: var(--dark);
}

/* Module styling for CTA */
.view-case-btn .cta-module {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: flex-end;
    width: 32px;
    height: 32px;
    border: 1px solid var(--dark);
    background-color: var(--light);
    position: relative;
    transition: transform var(--transition-medium) cubic-bezier(0.16, 1, 0.3, 1),
                border-color var(--transition-fast) ease,
                border-width var(--transition-fast) ease,
                box-shadow var(--transition-medium) ease,
                background-color var(--transition-fast) ease;
    margin-right: 10px;
}

.view-case-btn:hover .cta-module {
    border: 1.2px solid var(--dark);
    box-shadow: 0 0 6px rgba(169, 176, 178, 0.3);
    background-color: var(--cool);
}

.view-case-btn .module-indicator {
    width: 4px;
    height: 4px;
    border-radius: 50%;
    margin-bottom: 2px;
    position: relative;
    opacity: .72;
    transition: opacity var(--transition-fast) ease, transform var(--transition-fast) ease;
}

/* Project-specific module indicator colors */
#project1 .view-case-btn .module-indicator {
    background-color: var(--warm);
}

#project2 .view-case-btn .module-indicator {
    background-color: var(--blue);
}

#project3 .view-case-btn .module-indicator {
    background-color: var(--pink);
}

#project4 .view-case-btn .module-indicator {
    background-color: var(--purple);
}

#project5 .view-case-btn .module-indicator {
    background-color: var(--darkblue);
}

#project6 .view-case-btn .module-indicator {
    background-color: var(--cyan);
}

.view-case-btn .module-indicator .pulse-ring {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    width: 100%;
    height: 100%;
    border-radius: 50%;
    opacity: 0.5;
}

/* START CLEAN-FIX-P5-S7C2B-M2-SET3-PULSE
   Set 3 tier selection (2026-04-16): Medium M-1 Gentle Swell.

   Element: .view-case-btn .module-indicator .pulse-ring
   Scope: Desktop expanded state, P1 only (the only project with a
   .view-case-btn CTA — "view case study" action). Not used on mobile.
   Variation source: test-pulse-variations.html line 174-178 (medium-gentle-swell).
   Tier rationale: Density-neutral since Set 3 only fires on P1. Uses Medium
   but distinct cadence (2400ms) from Set 2's 3600ms, creating polyrhythm
   on P1. Both scale-based but different scale ranges (1→1.15 vs 1→1.12)
   and different timing functions (ease-in-out vs cubic-bezier) provide
   visual differentiation.

   Replaces: Legacy shared `module-pulse-ring 2s infinite`. Sets 2 and 3
   both used this keyframe name (duplicate-keyframe bug where L1170 +
   L2935 definitions existed with different bodies but only the later one
   won via cascade). Each set now gets a dedicated keyframe.

   Keyframe body preserves translate(-50%,-50%) centering transform.

   Dependencies: None. Reads --accent-rgb per-project chain.

   Reversibility: Search CLEAN-FIX-P5-S7C2B-M2-SET3-PULSE, delete between
   START/END markers. Restore `animation: module-pulse-ring 2s infinite`
   on the selector. Legacy keyframe below remains available.

   Verify:
   - XL desktop, expand P1 → view-case-btn pulse-ring swells scale 1↔1.15 +
     opacity 0.6↔0.85 over 2400ms ease-in-out.
   - Expand P2-P6 → no view-case-btn (DOM-absent), rule doesn't fire.
   - prefers-reduced-motion: reduce → suppressed (pending C2-6 gate ext).
*/
.view-case-btn .module-indicator .pulse-ring.animate {
    /* R4-PHASE-III-PULSE-REDO 2026-04-28: SET3 M-1 Gentle Swell (set3-viewcase-gentle-swell 2400ms)
       superseded by M-5 Slow Breathe per Phase II Section 4.5 user-decided pulse mapping.
       Tier 2 Medium. Source: test-pulse-variations.html line 203. Slightly less aggressive scale
       (1.12 vs prior 1.15) + adjusted opacity (0.65 vs 0.6) + slower cadence (3600ms vs 2400ms).
       Per-project accent visible via .pulse-ring base background-color (existing
       #projectN .view-case-btn .module-indicator .pulse-ring rules). translate(-50%,-50%)
       preserved in keyframe to maintain centering during scale animation. */
    animation: medium-slow-breathe 3600ms cubic-bezier(0.37, 0, 0.63, 1) infinite;
}

@keyframes medium-slow-breathe {
    0%, 100% { transform: translate(-50%, -50%) scale(1);    opacity: 0.65; }
    50%      { transform: translate(-50%, -50%) scale(1.12); opacity: 0.85; }
}
/* END CLEAN-FIX-P5-S7C2B-M2-SET3-PULSE */

/* Legacy keyframe retained for revert trace — no consumer after SET2-PULSE
   and SET3-PULSE markers land (this L1170 definition was cascade-losing to
   the L~2935 definition; now both are dead code). Scheduled for removal in
   Phase 6 streamlining (Cluster #1 pulse keyframe unification). */
@keyframes module-pulse-ring {
    0% { transform: translate(-50%, -50%) scale(0.8); opacity: 0.6; }
    50% { transform: translate(-50%, -50%) scale(1.5); opacity: 0.2; }
    100% { transform: translate(-50%, -50%) scale(0.8); opacity: 0.6; }
}

.view-case-btn .module-name {
    font-size: var(--font-size-small);
    font-weight: 400;
    color: var(--dark);
    transition: transform var(--transition-medium) ease,
                color var(--transition-medium) ease;
}

/* Rotate module name on hover - counter-clockwise */
.view-case-btn:hover .module-name {
    transform: rotate(-90deg);
    color: var(--black);
}

/* 3D Cube Effect for CTA */
.view-case-btn .cube-wrapper {
    perspective: 600px;
    position: relative;
    width: 120px;
    height: 24px;
    flex-grow: 1;
}

.view-case-btn .cube {
    width: 100%;
    height: 100%;
    position: relative;
    transform-style: preserve-3d;
    transition: transform var(--transition-medium) cubic-bezier(0.19, 1, 0.22, 1);
}

.view-case-btn:hover .cube {
    transform: rotateX(180deg);
}

.view-case-btn .cube-face {
    position: absolute;
    width: 100%;
    height: 100%;
    display: flex;
    align-items: center;
    justify-content: center;
    backface-visibility: hidden;
    font-size: var(--font-size-small);
    text-transform: uppercase;
    letter-spacing: 0.2px;
    font-family: var(--font-primary);
}

.view-case-btn .cube-face.front {
    transform: translateZ(12px);
    background-color: transparent;
    font-weight: 400;
    color: var(--darkest);
}

.view-case-btn .cube-face.back {
    transform: rotateX(180deg) translateZ(12px);
    background-color: transparent;
    color: var(--dark);
    font-weight: 700;
    position: relative;
}

/* Add line effect to cube back face */
.view-case-btn .cube-face.back::after {
    content: '';
    position: absolute;
    bottom: -2px;
    left: 0;
    width: 0;
    height: 1px;
    transition: width var(--transition-medium) cubic-bezier(0.16, 1, 0.3, 1);
}

.view-case-btn:hover .cube-face.back::after {
    width: 100%;
}

/* Project-specific back line colors */
#project1 .view-case-btn .cube-face.back::after {
    background-color: var(--warm);
}

#project2 .view-case-btn .cube-face.back::after {
    background-color: var(--blue);
}

#project3 .view-case-btn .cube-face.back::after {
    background-color: var(--pink);
}

#project4 .view-case-btn .cube-face.back::after {
    background-color: var(--purple);
}

#project5 .view-case-btn .cube-face.back::after {
    background-color: var(--darkblue);
}

#project6 .view-case-btn .cube-face.back::after {
    background-color: var(--cyan);
}

.view-case-btn .cube-face.top,
.view-case-btn .cube-face.bottom,
.view-case-btn .cube-face.left,
.view-case-btn .cube-face.right {
    background-color: transparent;
    opacity: 0.8;
}

.view-case-btn .cube-face.top {
    height: 24px;
    transform: rotateX(90deg) translateZ(12px);
}

.view-case-btn .cube-face.bottom {
    height: 24px;
    transform: rotateX(-90deg) translateZ(12px);
}

.view-case-btn .cube-face.left {
    width: 24px;
    height: 100%;
    left: 50%;
    margin-left: -12px;
    transform: rotateY(-90deg) translateZ(12px);
}

.view-case-btn .cube-face.right {
    width: 24px;
    height: 100%;
    left: 50%;
    margin-left: -12px;
    transform: rotateY(90deg) translateZ(12px);
}

/* ========================================
   PROJECT MODULE INDICATOR
   ======================================== */

/* Project Module Indicator */
.project-module {
    display: flex;
    align-items: center;
    gap: 10px;
}

.project-module .module-indicator {
    width: 8px;
    height: 8px;
    border-radius: 50%;
    position: relative;
    transition: transform var(--transition-fast) ease;
}

/* Project-specific module colors */
#project1 .project-module .module-indicator {
    background-color: var(--warm);
}

#project2 .project-module .module-indicator {
    background-color: var(--blue);
}

#project3 .project-module .module-indicator {
    background-color: var(--pink);
}

#project4 .project-module .module-indicator {
    background-color: var(--purple);
}

#project5 .project-module .module-indicator {
    background-color: var(--darkblue);
}

#project6 .project-module .module-indicator {
    background-color: var(--cyan);
}

.project-module .pulse-ring {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    width: 100%;
    height: 100%;
    border-radius: 50%;
    opacity: 0.5;
}

/* Project-specific pulse colors */
#project1 .project-module .pulse-ring {
    background-color: rgba(121, 126, 128, 0.5); /* warm */
}

#project2 .project-module .pulse-ring {
    background-color: rgba(0, 0, 255, 0.5); /* blue */
}

#project3 .project-module .pulse-ring {
    background-color: rgba(255, 40, 145, 0.5); /* pink */
}

#project4 .project-module .pulse-ring {
    background-color: rgba(170, 0, 255, 0.5); /* purple */
}

#project5 .project-module .pulse-ring {
    background-color: rgba(7, 7, 51, 0.5); /* darkblue */
}

#project6 .project-module .pulse-ring {
    background-color: rgba(0, 217, 255, 0.5); /* cyan */
}

/* START CLEAN-FIX-P5-S7C2B-M2-SET4-PULSE
   Set 4 tier selection (2026-04-16): Medium M-6 Ring Expand.

   Element: .project-module .pulse-ring
   Scope: Desktop expanded state AND mobile active state (mirror —
   user picked same animation across both implementations). Fires × N
   module cards per column.
   Variation source: test-pulse-variations.html line 209-213 (medium-ring-expand).
   Tier rationale: User accepted 3rd Medium slot (Sets 2 + 3 + 4 all
   Medium). Ring-based vocabulary distinguishes Set 4 from scale-based
   Sets 2/3 — creates two motion families in the composition. Set 4
   echoes Set 1 H-5 Heavy ripple geometry (also ring-based), tying
   the expanded column together visually.

   Replaces: Legacy `pulse-ring 2s infinite` (scale 1→2→1 + opacity
   0.5→0→0.5). New keyframe set4-project-module-ring-expand uses
   box-shadow expansion (0→18px) with opacity fade — element itself
   stays static at translate(-50%,-50%) center anchor.

   Background-color override: `.animate` state transitions the element
   background from per-project rgba(accent, 0.5) filled-ring to
   transparent, so only the box-shadow ring reads. Prevents "filled
   ring + expanding shadow" compound that would read busy at × N
   density. When not animating, the pulse-ring retains original filled
   appearance.

   Keyframe body preserves translate(-50%,-50%) centering transform —
   present in base rule at `.project-module .pulse-ring`, NOT in
   keyframe (keyframe only animates box-shadow + transparent bg).

   Dependencies: 7B.0b --accent-rgb :root hoist (388da45) for per-project
   ring color. Without hoist, fallback rgba(121, 126, 128, x) paints.

   Reversibility: Search CLEAN-FIX-P5-S7C2B-M2-SET4-PULSE, delete between
   START/END markers. Restore `animation: pulse-ring 2s infinite` +
   remove background-color:transparent override. Legacy pulse-ring
   keyframe below remains available.

   Verify:
   - XL desktop, expand any project → each .project-module shows its
     pulse-ring expanding outward as box-shadow ring 0→18px over 2700ms.
     Inner filled ring hidden during animation.
   - Mobile active state → same animation fires. Fewer modules typically
     visible on mobile (1-3 vs N desktop), so density reads lighter.
   - Cycle P1→P6 → ring color tracks --accent-rgb per-project accent.
   - prefers-reduced-motion: reduce → suppressed (pending C2-6 gate ext).
*/
.project-module .pulse-ring.animate {
    /* R4-PHASE-III-PULSE-REDO 2026-04-28: SET4 M-6 Ring Expand (set4-project-module-ring-expand
       2700ms; was hiding filled ring via background-color: transparent for shadow-only visual)
       superseded by H-8 Explosive Scale per Phase II Section 4.5 user-decided pulse mapping.
       Tier 1 Heavy. Source: test-pulse-variations.html line 163. Dramatic transform: scale
       (1 -> 2.2 -> 0.8 -> 1.8 -> 1.1) with opacity shifts. Per-project accent visible via
       .pulse-ring base background-color (existing #projectN .project-module .pulse-ring rules
       at line 1412+). REMOVED `background-color: transparent` from prior M-6 (now we WANT the
       filled ring visible since H-8 is transform-only - the per-project ring scaling IS the
       visible accent expression). translate(-50%,-50%) preserved in keyframe to maintain
       centering during scale animation. PAIRED with index.html edits at lines 548 + 985 to
       add `.animate` class on P2 + P3 project-module pulse-rings (other 4 projects already
       have .animate per HTML inventory). */
    animation: heavy-explosive-scale 4200ms cubic-bezier(0.25, 0.46, 0.45, 0.94) infinite;
}

@keyframes heavy-explosive-scale {
    0%, 85%, 100% { transform: translate(-50%, -50%) scale(1);   opacity: 0.9; }
    15%           { transform: translate(-50%, -50%) scale(2.2); opacity: 0.3; }
    30%           { transform: translate(-50%, -50%) scale(0.8); opacity: 1; }
    45%           { transform: translate(-50%, -50%) scale(1.8); opacity: 0.5; }
    60%           { transform: translate(-50%, -50%) scale(1.1); opacity: 0.9; }
}
/* END CLEAN-FIX-P5-S7C2B-M2-SET4-PULSE */

/* Legacy keyframe retained for revert trace — no consumer after SET4-PULSE
   marker lands. Scheduled for removal in Phase 6 streamlining (Cluster #1). */
@keyframes pulse-ring {
    0% {
        transform: translate(-50%, -50%) scale(1);
        opacity: 0.5;
    }
    50% {
        transform: translate(-50%, -50%) scale(2);
        opacity: 0;
    }
    100% {
        transform: translate(-50%, -50%) scale(1);
        opacity: 0.5;
    }
}

.project-module .module-label {
    font-size: var(--font-size-specialized);
    font-weight: 700;
    color: var(--dark);
    text-transform: uppercase;
    letter-spacing: 1px;
    font-family: var(--font-primary);
}

/* Project column active state to ensure expanded view shows */
.project-column.active .project-expanded {
    opacity: 1;
    display: flex;
    /* START CLEAN-FIX-P5-S7C2-CONTENT-FADE-SYNC — @starting-style half
       Paired with base rule transition update at line ~810. Declares the
       "before transition" opacity value so the opacity fade has a valid
       starting point when display flips from none → flex. Without this,
       the browser skips the transition and content appears instantly. */
    @starting-style {
        opacity: 0;
    }
    /* END CLEAN-FIX-P5-S7C2-CONTENT-FADE-SYNC */
}

/* Hide collapsed view when active */
.project-column.active .project-collapsed {
    opacity: 0;
    pointer-events: none;
    display: none;
}

/* Active column styling - ensure mockups are visible */
.project-column.active .mockups-column,
.project-column.active .mockups-marquee-container {
    display: block;
    opacity: 1;
}

/* Hide collapsed view when expanded */
.project-column.active .project-collapsed {
    opacity: 0;
    pointer-events: none;
}

/* ========================================
   EXPANDED VIEW - HEADER COMPONENTS
   ======================================== */

/* Project Header in Expanded View */
.project-header {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
}

.project-header .coords-system {
    width: 120px;
    height: 120px;
    position: relative;
    transition: all var(--transition-medium) ease;
}

.project-header .project-number {
    position: absolute;
    top: 6px;  /* coord-line x (0px) + 6px below */
    left: 6px; /* coord-line y (3px) + 3px to right */
    font-size: var(--font-size-super-huge);
    font-weight: 900;
    line-height: 0.9;
    opacity: 0.6;
}

/* Coordinate system accessing state */
.coords-system.accessing .coord-point {
    animation: blink 1s infinite;
}

@keyframes blink {
    0%, 100% { opacity: 1; }
    50% { opacity: 0.2; }
}

/* Global Coordinate System Line Colors */
.coords-system .coord-line {
    position: absolute;
    background-color: var(--dark) !important; /* UPDATED: Collapsed projects coord-line color */
    transition: all var(--transition-medium) ease;
}

.coords-system.accessing .coord-line {
    background-color: var(--dark) !important; /* UPDATED: Expanded projects coord-line color should be dark */
}

.coords-system .coord-line.x {
    top: 0; /* Aligned with coord-line y to ensure they meet at same point */
    left: 3px; /* Same as coord-line y to ensure they meet */
    height: 1px;
    width: calc(100% - 3px);
}

.coords-system .coord-line.y {
    top: 0;
    left: 3px;
    width: 1px;
    height: calc(100% - 0px);
}

/* Already handled above - removing duplicate */

/* Project Title Expanded */
.project-title-expanded {
    position: relative;
    margin-left: 0; /* Remove left margin since items are now stacked */
}

.project-title-expanded h2 {
    font-size: var(--font-size-super-huge);
    font-weight: 800;
    text-transform: uppercase;
    margin: 0;
    line-height: 1;
}

.title-accent {
    position: absolute;
    top: 5px;
    right: -10px;
    width: 15px;
    height: 15px;
    opacity: 0.7;
}

/* ========================================
   EXPANDED VIEW - CONTENT COMPONENTS
   ======================================== */

/* Project Subtitle & Impact Statement - Styles moved to earlier section */

/* Highlight text in project impact */
.highlight {
    font-weight: 700;
}

/* Work Categories as Tags */
.work-categories {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
}

.category-tag {
    font-size: var(--font-size-specialized);
    padding: 4px 10px;
    background-color: var(--lightest);
    border-radius: 3px;
    font-weight: 500;
    text-transform: uppercase;
    border-left: 2px solid; /* Border takes the project's accent color */
    color: var(--black);
    font-family: var(--font-primary);
}

/* Overview components moved to OVERVIEW TRIGGER section below */

/* ========================================
   PROJECT OVERVIEW - EXPANDABLE CONTENT
   ======================================== */

/* Project Overview Section - HIDDEN (using overlay instead) */
.project-overview {
    display: none !important; /* Hide inline overview - using overlay approach */
    overflow: hidden;
    transition: max-height var(--transition-slow) cubic-bezier(0.16, 1, 0.3, 1);
    position: relative;
}

.project-overview.expanded {
    max-height: 160px;
    margin-bottom: 20px;
}

/* Overview marquee container for projects 2-5 */
.overview-marquee {
    position: relative;
    width: 100%;
    height: 160px;
    overflow: hidden;
}

/* Overview scroller for marquee effect */
.overview-scroller {
    animation-name: scrollTheScroller;
    animation-duration: 240s; /* Slow speed for readability */
    animation-timing-function: linear;
    animation-iteration-count: infinite;
    animation-play-state: paused;
    width: 100%;
    transform: translateZ(0);
    will-change: transform;
    backface-visibility: hidden;
}

.project-overview.expanded .overview-scroller {
    animation-play-state: running;
    animation-delay: 4.8s;
}

.overview-scroller.paused {
    animation-play-state: paused;
}

/* Overview content items */
.overview-content-item {
    font-family: var(--font-secondary);
    font-size: var(--font-size-standard);
    line-height: 1.6;
    color: var(--dark);
    padding-left: 20px;
    padding-bottom: 15px;
    position: relative;
}

.overview-content-item::after {
    content: '';
    display: block;
    width: 80%;
    height: 1px;
    background-color: var(--cool);
    margin: 15px auto 0 auto;
}

.overview-content-item p {
    margin-bottom: 15px;
}

@keyframes scrollTheScroller {
    0% {
        transform: translateY(0);
    }
    100% {
        transform: translateY(-50%);
    }
}

/* Projects 1 & 6 - Static content (no marquee) */
#project1 .project-overview.expanded,
#project6 .project-overview.expanded {
    background-color: var(--darkest);
    padding: 20px;
    max-height: 300px;
    overflow: hidden;
}

#project1 .overview-content,
#project6 .overview-content,
#project1 .overview-content-vertical,
#project6 .overview-content-vertical {
    color: var(--white);
}

#project1 .overview-content p,
#project6 .overview-content p,
#project1 .overview-content-vertical p,
#project6 .overview-content-vertical p {
    color: var(--white);
    margin-bottom: 15px;
}

#project1 .overview-content strong,
#project6 .overview-content strong,
#project1 .overview-content-vertical strong,
#project6 .overview-content-vertical strong {
    color: var(--white);
    font-weight: 700;
}

/* Removed conditional spacing rules - using consistent grid gap instead */
/* Elements now maintain equal spacing regardless of overview state */

/* ========================================
   EXPANDED VIEW - MOCKUPS COLUMN
   ======================================== */

/* Mockups Container */
.mockups-marquee-container {
    position: absolute;
    top: var(--spacing-60); /* 60px = 10×6 */
    left: 0;
    width: 100%;
    height: calc(100% - var(--spacing-60));
    overflow: hidden;
    padding: 0; /* Padding moved to masonry container */
    opacity: 0; /* Start hidden */
    transition: opacity 0.35s cubic-bezier(0.22, 1, 0.36, 1);
    /* GPU Acceleration for better performance */
    transform: translateZ(0);
    will-change: contents;
    backface-visibility: hidden;
    contain: layout style paint;
}

.project-column.active .mockups-marquee-container {
    opacity: 1;
}

/* Mockups Header */
.mockups-header {
    width: 100%;
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 12px 18px; /* 2×6n vertical, 3×6n horizontal */
    border-bottom: 2px solid var(--dark);
    position: relative;
    min-height: 48px; /* 8×6n — allows title to wrap without clipping */
    box-sizing: border-box;
}

/* Ensure proper flex layout for header sections */
.mockups-header > * {
    flex: 1;
    display: flex;
    align-items: center;
}

/* Left - Title */
.mockups-title {
    justify-content: flex-start;
    text-transform: uppercase;
    font-weight: 700;
    color: var(--dark);
    font-size: var(--font-size-specialized);
    letter-spacing: 0.5px;
    font-family: var(--font-primary);
    /* START CLEAN-FIX-P5-S4B-MOCKUPS-TITLE-WRAP */
    /* Allow title to wrap at narrow widths (LG max ~1199px) instead of truncating
       min-width:0 overrides flex default; white-space:normal allows wrapping
       To revert: Delete these 5 properties */
    min-width: 0;
    overflow-wrap: break-word;
    white-space: normal;
    line-height: 1.4;
    padding-right: var(--spacing-12);
    /* END CLEAN-FIX-P5-S4B-MOCKUPS-TITLE-WRAP */
}

/* Center - Speed Selection */
.speed-selection {
    position: absolute;
    left: 50%;
    transform: translateX(-50%);
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 2px;
}

/* Right - Pause Control */
.pause-control {
    flex: 0 0 auto;
    display: none; /* Hide by default */
    align-items: center;
    justify-content: flex-end;
    gap: 2px; /* 2px gap between pause and restart buttons */
}

/* Show pause control for projects 2-6 */
#project2 .pause-control,
#project3 .pause-control,
#project4 .pause-control,
#project5 .pause-control,
#project6 .pause-control {
    display: flex;
}

/* Right - Controls */
.mockups-controls {
    justify-content: flex-end;
    gap: 10px;
    display: flex;
    align-items: center;
    flex-shrink: 0;
}

/* START CLEAN-FIX-P5-S6.5-MOCKUPS-HEADER-TWOLINE
   Two-line mockups-header layout at narrow desktop widths (820-1199px).

   Root cause: At LG min 992×700 and narrow desktop widths, the
   .mockups-header single-row layout (title + absolutely-centered
   .speed-selection + right-aligned .pause-control) runs out of
   horizontal space. The mockups-title text is visually cut off /
   overlapped by the center-positioned .speed-selection element.
   position: absolute doesn't respect flex wrap, so P5-S4B's title
   text-wrapping fix alone isn't sufficient — the controls still
   cover the title horizontally.

   Fix (P5-S6.5 Issue #11): At 820-1199px specifically, restructure
   .mockups-header into two rows:
     Row 1: .mockups-title (full width via flex-basis: 100%)
     Row 2: .speed-selection (left-aligned, flowed in source order)
            + .pause-control (right-aligned via margin-left: auto),
            with gap in middle consuming remaining horizontal space

   Strategy:
     1. flex-wrap: wrap on .mockups-header enables row 2
     2. row-gap: var(--spacing-6) for vertical spacing between rows
     3. min-height: auto overrides base 48px since two rows are taller
     4. .mockups-title { flex: 1 0 100% } forces onto its own row
     5. .mockups-title { padding-right: 0 } since no sibling same-row
     6. .speed-selection { position: static; transform: none } removes
        absolute positioning so it flows in row 2
     7. .speed-selection { flex: 0 0 auto; justify-content: flex-start }
        pushes to left edge of row 2
     8. .pause-control { margin-left: auto } pushes to right edge,
        margin consumes remaining space = gap in middle the user requested

   Scope: (min-width: 820px) and (max-width: 1199px). At XL 1200+,
   container is wide enough for base single-row layout. At mobile
   ≤819px, entirely different rendering path (mobile overlay).

   P1 note: P1 has .pause-control { display: none } by default (only
   P2-P6 show it per #project2-6 override at line 1648). For P1 at the
   narrow band, row 2 contains only .speed-selection (left-aligned,
   no right sibling) — margin-left:auto has no effect since it's
   display:none. This is graceful degradation — P1 shows speed-selection
   left-aligned alone on row 2. Acceptable.

   Evidence: User-reported visual issue 2026-04-13: "mockups-title
   element cut off visually. would rather move to two lines where
   mockup-title on top line, left- and right-button sub-groups
   horizontally split second/bottom line with each pushing to left-
   most and right-most sides of mockups-header (with gap in middle)"
   — Image #15 in P5-S6.5 diagnostic session.

   If not effective: (1) Check .speed-selection's position: static
   actually overrides base position: absolute (cascade order — @media
   loads after base). (2) Verify .pause-control's margin-left: auto
   pushes to right — if not, fallback to justify-content: space-between
   on .mockups-header. (3) Runtime-check row 2 vertical alignment via
   inherited align-items: center from base .mockups-header.

   Stopping condition: If two-row layout causes .mockups-header to
   grow too tall and push mockups area down, reduce row-gap to 0 or
   compress control button sizes via separate sub-marker.

   Verification: Pre-flight at LG min 992×700, LG max 1199×800, MD
   max 991×1200 (all should apply — two-row), XL min 1200×800 (should
   NOT apply — single-row restored), SM ≤819 (should NOT apply —
   different path).

   To revert: Search CLEAN-FIX-P5-S6.5-MOCKUPS-HEADER-TWOLINE,
   delete everything between START and END markers. */
@media (min-width: 820px) and (max-width: 1199px) {
    .mockups-header {
        flex-wrap: wrap;
        row-gap: var(--spacing-6);
        min-height: auto;
    }
    .mockups-title {
        flex: 1 0 100%;
        padding-right: 0;
        justify-content: center;  /* Row 1 centered per user feedback 2026-04-14 */
        text-align: center;       /* Fallback for text alignment inside flex container */
    }
    .speed-selection {
        position: static;
        transform: none;
        flex: 0 0 auto;
        justify-content: flex-start;
    }
    .pause-control {
        margin-left: auto;
    }
    /* .mockups-marquee-container top/height compensation for taller 2-row header.
       Base rule at line 1566-1570 uses top: var(--spacing-60) (60px) + height: calc(100% - 60px),
       assuming a single-row ~48px header. With the 2-row layout above, header height grows to
       ~76.5px computed (12pt+12pb + 14.6 title + 6 row-gap + 30 controls + 2 border). Rounding
       up to next 6n multiple = 78px (13×6n). Override top + height to match, preventing the
       mockups content from overlapping the bottom edge of the 2-row header.
       Design system note: no --spacing-78 token exists (closest is --spacing-72 or --spacing-96
       at 12×6n / 16×6n respectively). Using literal 78px (13×6n compliant) with inline comment. */
    .mockups-marquee-container {
        top: 78px;                      /* 13×6n, was var(--spacing-60) = 60px */
        height: calc(100% - 78px);      /* matches top offset */
    }
}
/* END CLEAN-FIX-P5-S6.5-MOCKUPS-HEADER-TWOLINE */


/* ============================================================================
   START CLEAN-FIX-P5-S6.5c-R4-MOCKUPS-HEADER-SPECIFICITY-FIX (2026-04-28)
   ============================================================================
   Specificity collision fix for 2-row mockups-header layout at 820-991.

   Surfaced via Phase II Preset 1 (iPad Air 834×1194) testing 2026-04-28
   + 3-agent review (ui-ninja design, code-review-analyst structural,
   Plan agent strategy) — all three signed off.

   Root cause: the existing CLEAN-FIX-P5-S6.5-MOCKUPS-HEADER-TWOLINE block
   above (1964-1997) attempts to override .speed-selection and .pause-control
   to `flex: 0 0 auto` at @media (820-1199). But `.mockups-header > * {
   flex: 1 }` at line 1831 carries specificity (0,2,0) while the @media
   overrides on `.speed-selection` (line 1976) and `.pause-control` are
   each (0,1,0) — they LOSE the specificity contest. Result at narrow widths:
   speed-selection and pause-control compute `flex: 1 1 0%`, causing wrap to
   separate rows. User reports 3-row layout (title / speed alone / pause alone)
   instead of intended 2-row layout (title / speed+pause same row).

   Fix: match (0,2,0) specificity via the child-combinator selectors
   `.mockups-header > .speed-selection` and `.mockups-header > .pause-control`.
   Same specificity as parent `.mockups-header > *` rule; placed AFTER the
   parent rule in file source order — cascade-order tie-breaker wins.

   Why a SEPARATE @media block from the parent CLEAN-FIX-TWOLINE block:
   - Maintains atomic-revert isolation (this chunk reverts independently;
     parent block stays intact).
   - Narrower scope (820-991 vs parent's 820-1199) per user mandate
     2026-04-28 to minimize regression risk on LG; Phase II Preset 4
     (LG Min 992×600) sweep will validate whether to broaden scope.
   - The (0,2,0) specificity fight is the REASON for separate placement,
     NOT a scope-of-effect difference. Phase 10.19 cleanup target: fold
     into parent CLEAN-FIX-TWOLINE block if LG scope alignment is approved.

   Selector behavior:
   - `.mockups-header > .speed-selection` does NOT match
     `.mobile-mockups-header > .speed-selection` (distinct class names; child
     combinator does not traverse class similarity). Mobile carousel header at
     index.html:3173 is unaffected — confirmed by code-review-analyst.

   `!important` discipline: ZERO new `!important` declarations per CLAUDE.md.

   To revert: search CLEAN-FIX-P5-S6.5c-R4-MOCKUPS-HEADER-SPECIFICITY-FIX
   and delete everything between START and END markers.
   ============================================================================ */
@media (min-width: 820px) and (max-width: 991px) {
    .mockups-header > .speed-selection,
    .mockups-header > .pause-control {
        flex: 0 0 auto;
    }
}
/* END CLEAN-FIX-P5-S6.5c-R4-MOCKUPS-HEADER-SPECIFICITY-FIX */


/* Control Buttons - Brutalist Style */
.control-btn {
    width: 30px;
    height: 30px;
    display: flex;
    align-items: center;
    justify-content: center;
    background-color: var(--lightest);
    border: none;
    font-size: var(--font-size-small);
    color: var(--dark);
    cursor: pointer;
    transition: background-color var(--transition-fast) ease, 
                color var(--transition-fast) ease,
                opacity var(--transition-fast) ease;
    font-family: var(--font-primary);
    border-left: 2px solid var(--dark); /* Brutalist accent */
}

.control-btn:hover:not(.disabled) {
    background-color: var(--light);
    color: var(--black);
}

.control-btn.active {
    background-color: var(--dark);
    color: var(--white);
}

.control-btn.disabled {
    opacity: 0.4;
    cursor: default;
}

/* Restart button - icon rotation only */

.restart-btn.animating {
    color: transparent; /* Hide original text during animation */
}

.restart-btn.animating::before {
    content: '↻';
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    color: var(--dark);
    font-weight: 700;
    animation: icon-spin 0.6s ease-out forwards;
    z-index: 2; /* Ensure it appears above the text */
    pointer-events: none; /* Prevent interference */
    background-color: var(--lightest); /* Match button background */
}

@keyframes icon-spin {
    0% { 
        transform: rotate(0deg);
    }
    100% { 
        transform: rotate(360deg);
    }
}

/* For projects 1 and 6, hide center content */
#project1 .mockups-header-center,
#project6 .mockups-header-center {
    visibility: hidden;
}

/* Speed Selection UI - Only for projects 2-5 */
.speed-selection {
    display: none; /* Hide by default */
}

/* Show speed selection for projects 2-5 */
#project2 .speed-selection,
#project3 .speed-selection,
#project4 .speed-selection,
#project5 .speed-selection {
    display: flex;
}


/* All speed buttons now have left borders */

.speed-option {
    /* Base styles */
    display: inline-flex;
    font-family: var(--font-primary);
    font-size: var(--font-size-large);
    height: 30px;
    min-width: 40px;
    padding: 0 10px;
    border: none;
    border-left: 2px solid var(--dark);
    background-color: var(--lightest);
    cursor: pointer;
    text-align: center;
    align-items: center;
    justify-content: center;
    margin: 0;
    
    /* Transitions */
    transition: background-color var(--transition-fast) ease, 
                color var(--transition-fast) ease,
                transform 0.2s ease-out;
    
    /* Animation requirements */
    position: relative;
    overflow: hidden;
    transform-origin: center;
    backface-visibility: hidden;
    -webkit-backface-visibility: hidden;
}

.speed-option:hover {
    background-color: var(--light);
    color: var(--black);
}

.speed-option.active {
    background-color: var(--dark);
    color: var(--white);
}

/* Speed button animations */

/* Base animation for all speed buttons */
.speed-option.clicked {
    color: transparent;
}

.speed-option.clicked::before {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    color: var(--dark);
    font-weight: 700;
    z-index: 1; /* Ensure it appears above the text */
    background-color: var(--lightest); /* Match button background */
    pointer-events: none;
}

/* Quick active feedback for all buttons */
.speed-option:active,
.pause-btn:active,
.restart-btn:active {
    background-color: var(--light) !important;
    transition: background-color 0.2s ease;
}

/* Keep original background during animations */
.speed-option.clicked,
.pause-btn.minimizing,
.pause-btn.expanding,
.restart-btn.animating {
    background-color: var(--lightest) !important;
}

/* Slow speed animation */
.speed-option[data-speed="slow"].clicked::before {
    content: '⊷';
    animation: speed-rise-slow 0.9s ease-out 0.2s forwards;
}

@keyframes speed-rise-slow {
    0% { 
        transform: translateY(30px); 
        opacity: 0; 
    }
    50% { 
        transform: translateY(-5px); 
        opacity: 1; 
    }
    100% { 
        transform: translateY(0); 
        opacity: 1; 
    }
}

/* Default speed animation */
.speed-option[data-speed="default"].clicked::before {
    content: '⍛';
    animation: speed-rise-medium 0.6s ease-out 0.2s forwards;
}

@keyframes speed-rise-medium {
    0% { 
        transform: translateY(30px); 
        opacity: 0; 
    }
    40% { 
        transform: translateY(-8px); 
        opacity: 1; 
    }
    100% { 
        transform: translateY(0); 
        opacity: 1; 
    }
}

/* Fast speed animation */
.speed-option[data-speed="fast"].clicked::before {
    content: '⊶';
    animation: speed-rise-fast 0.3s ease-out 0.2s forwards;
}

@keyframes speed-rise-fast {
    0% { 
        transform: translateY(30px); 
        opacity: 0; 
    }
    30% { 
        transform: translateY(-10px); 
        opacity: 1; 
    }
    100% { 
        transform: translateY(0); 
        opacity: 1; 
    }
}

/* Pause button styling - CONSOLIDATED */
.pause-btn {
    /* Base styles */
    display: inline-flex;
    font-family: var(--font-primary);
    font-size: var(--font-size-small);
    height: 30px;
    width: 30px;
    padding: 0;
    border: none;
    border-left: 2px solid var(--dark);
    background-color: var(--lightest);
    cursor: pointer;
    text-align: center;
    align-items: center;
    justify-content: center;
    margin: 0;
    font-weight: 700;
    color: var(--dark);
    letter-spacing: -2px; /* Bring the vertical lines closer together */
    
    /* Transitions */
    transition: background-color var(--transition-fast) ease, 
                color var(--transition-fast) ease;
    
    /* Animation requirements */
    position: relative;
    overflow: hidden;
    transform-origin: center;
    backface-visibility: hidden;
    -webkit-backface-visibility: hidden;
}

.pause-btn:hover {
    background-color: var(--light);
    color: var(--black);
}

/* Button animation foundations - now integrated into individual button styles */

/* Pause/Play button animations */

/* Pause to Play animation (minimize to center) */
.pause-btn.minimizing {
    color: transparent;
}

.pause-btn.minimizing::before {
    content: '||';
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    color: var(--dark);
    font-weight: 700;
    letter-spacing: -2px;
    animation: pause-minimize 0.6s ease-out 0.2s forwards;
    z-index: 1; /* Ensure it appears above the text */
    background-color: var(--lightest); /* Match button background */
}

@keyframes pause-minimize {
    0% { 
        transform: scale(1); 
        opacity: 1; 
    }
    50% {
        transform: scale(0.7);
        opacity: 0.8;
    }
    100% { 
        transform: scale(0); 
        opacity: 0; 
    }
}

/* Play to Pause animation (expand from center) */
.pause-btn.expanding {
    color: transparent;
}

.pause-btn.expanding::before {
    content: '▶';
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    color: var(--dark);
    font-weight: 700;
    animation: play-expand 0.6s ease-out 0.2s forwards;
    z-index: 1; /* Ensure it appears above the text */
    background-color: var(--lightest); /* Match button background */
}

@keyframes play-expand {
    0% { 
        transform: scale(0); 
        opacity: 0; 
    }
    50% { 
        transform: scale(1.5); 
        opacity: 1; 
    }
    100% { 
        transform: scale(1); 
        opacity: 1; 
    }
}

/* Pause button states */
/* Letter-spacing already defined in main pause-btn styling above */

/* Restart button styling - CONSOLIDATED */
.restart-btn {
    /* Base styles */
    display: inline-flex;
    font-family: var(--font-primary);
    font-size: var(--font-size-small);
    height: 30px;
    width: 30px;
    padding: 0;
    border: none;
    border-left: 2px solid var(--dark);
    background-color: var(--lightest);
    cursor: pointer;
    text-align: center;
    align-items: center;
    justify-content: center;
    margin: 0;
    font-weight: 700;
    color: var(--dark);
    
    /* Transition (excluding transform which conflicts with animation) */
    transition: background-color var(--transition-fast) ease, 
                color var(--transition-fast) ease;
    
    /* Animation requirements */
    position: relative;
    overflow: hidden;
    transform-origin: center;
    backface-visibility: hidden;
    -webkit-backface-visibility: hidden;
    isolation: isolate; /* Create new stacking context */
}

.restart-btn:hover {
    background-color: var(--light);
    color: var(--black);
}

/* Ensure project1 restart button maintains light theme */
#project1 .mockups-header .restart-btn {
    background-color: var(--lightest);
    color: var(--dark);
    border-left: 2px solid var(--dark);
}

#project1 .mockups-header .restart-btn:hover {
    background-color: var(--light);
    color: var(--black);
}

/* Mockups Masonry Layout */
.mockups-masonry {
    display: flex;
    width: 100%;
    height: 100%;
    gap: var(--spacing-24); /* 24px = 4×6 - Horizontal gap between columns */
    padding: 0 var(--spacing-30); /* 30px horizontal padding */
}

.masonry-column {
    width: calc(50% - var(--spacing-12)); /* Half width minus half gap */
    position: relative;
    overflow: hidden;
    padding: 0; /* Remove padding - gap handles spacing */
}

/* Marquee Animation - Moved to v3-mockups-marquee.css for consolidation */
/* All marquee animation, speed controls, and keyframes are now in v3-mockups-marquee.css */
/* This eliminates CSS conflicts and provides single source of truth */

/* Mockup Items - DEPRECATED, use asset-container instead */
.mockup-item {
    width: 100%;
    margin-bottom: var(--spacing-42); /* 42px = 7×6 */
    transition: opacity 0.5s ease, transform 0.5s ease;
    flex-shrink: 0;
}

/* Triple spacing specifically for project1 mockup items */
#project1 .mockup-item {
    margin-bottom: var(--spacing-126); /* 126px = 21×6 (triple) */
}

/* Portfolio Images */
.portfolio-image {
    width: 100%;
    height: auto;
    display: block;
}

/* ========================================
   PROJECT-SPECIFIC ACCENT COLORS
   ======================================== */

/* Coord-lines should always be dark in expanded state */
/* Removed - coord-lines should be dark in expanded state */

/* Removed - coord-lines should be dark in expanded state */

/* Removed - coord-lines should be dark in expanded state */

/* Removed - coord-lines should be dark in expanded state */

/* Removed - coord-lines should be dark in expanded state */

/* Removed - coord-lines should be dark in expanded state */

/* Project-specific accent colors */
#project1 .title-accent, #project1 .accent-color {
    color: var(--warm);
}

#project2 .title-accent, #project2 .accent-color {
    color: var(--blue);
}

#project3 .title-accent, #project3 .accent-color {
    color: var(--pink);
}

#project4 .title-accent, #project4 .accent-color {
    color: var(--purple);
}

#project5 .title-accent, #project5 .accent-color {
    color: var(--darkblue);
}

#project6 .title-accent, #project6 .accent-color {
    color: var(--cyan);
}

/* Project-specific category tag accents */
#project1 .category-tag {
    border-color: var(--warm);
}

#project2 .category-tag {
    border-color: var(--blue);
}

#project3 .category-tag {
    border-color: var(--pink);
}

#project4 .category-tag {
    border-color: var(--purple);
}

#project5 .category-tag {
    border-color: var(--darkblue);
}

#project6 .category-tag {
    border-color: var(--cyan);
}

/* ========================================
   OVERVIEW TRIGGER - CUBE ANIMATION
   ======================================== */

/* Updated overview-trigger styling to mimic case-study-cta */
.overview-trigger {
    display: flex;
    align-items: center;
    padding: 8px 10px; /* Half the height of case-study-cta */
    border: none;
    cursor: pointer;
    position: relative;
    transition: all var(--transition-fast) ease;
    width: 100%;
    color: var(--dark);
    /* Removed margin-bottom - using grid gap for spacing */
}

.overview-trigger .cta-module {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: flex-end;
    width: 24px; /* Smaller than case-study-cta */
    height: 24px; /* Smaller than case-study-cta */
    position: relative;
    transition: transform var(--transition-medium) cubic-bezier(0.16, 1, 0.3, 1),
                opacity var(--transition-fast) ease;
    margin-right: 5px; /* Reduced margin for tighter spacing */
    opacity: 0.8; /* Default opacity */
}

.overview-trigger:hover .cta-module,
.overview-trigger.active .cta-module {
    opacity: 1; /* Full opacity on hover/active */
    transform: scale(1.1); /* Slight scale for hover feedback */
}

.overview-trigger .module-indicator {
    width: 4px;
    height: 4px;
    border-radius: 50%;
    margin-bottom: 2px;
    position: relative;
    opacity: .72;
    transition: opacity var(--transition-fast) ease, transform var(--transition-fast) ease;
}

/* Add subtle pulse animation to collapsed overview-trigger */
.overview-trigger:not(.active) .module-indicator {
    animation: subtle-pulse 3s ease-in-out infinite;
}

@keyframes subtle-pulse {
    0%, 100% {
        transform: scale(1);
        opacity: 0.72;
    }
    50% {
        transform: scale(1.3);
        opacity: 1;
    }
}

/* Project-specific module indicator colors for overview-trigger */
#project1 .overview-trigger .module-indicator {
    background-color: var(--warm);
}

#project2 .overview-trigger .module-indicator {
    background-color: var(--blue);
}

#project3 .overview-trigger .module-indicator {
    background-color: var(--pink);
}

#project4 .overview-trigger .module-indicator {
    background-color: var(--purple);
}

#project5 .overview-trigger .module-indicator {
    background-color: var(--darkblue);
}

#project6 .overview-trigger .module-indicator {
    background-color: var(--cyan);
}

.overview-trigger .module-name {
    font-size: var(--font-size-small);
    font-weight: 400;
    color: var(--dark); /* Default color: dark */
    transition: transform var(--transition-medium) ease, 
                color var(--transition-medium) ease;
}

.overview-trigger:hover .module-name,
.overview-trigger.active .module-name {
    transform: rotate(-90deg); /* Counter-clockwise rotation */
    color: var(--black); /* Hover color: black */
}

/* Cube wrapper for overview trigger */
.overview-trigger .cube-wrapper {
    perspective: 600px;
    position: relative;
    width: 120px;
    height: 24px;
    flex-grow: 1;
}

.overview-trigger .cube {
    width: 100%;
    height: 100%;
    position: relative;
    transform-style: preserve-3d;
    transition: transform var(--transition-medium) cubic-bezier(0.16, 1, 0.3, 1);
}

.overview-trigger:hover .cube,
.overview-trigger.active .cube {
    transform: rotateX(180deg);
}

.overview-trigger .cube-face {
    position: absolute;
    width: 100%;
    height: 100%;
    font-size: var(--font-size-small);
    font-weight: 700;
    text-transform: uppercase;
    color: var(--dark);
    display: flex;
    align-items: center;
    justify-content: flex-start;
    padding-left: 10px;
    backface-visibility: hidden;
    font-family: var(--font-primary);
}

.overview-trigger .cube-face.front {
    transform: translateZ(12px);
    background-color: transparent;
    font-weight: 400;
    color: var(--darkest);
}

.overview-trigger .cube-face.back {
    transform: rotateX(180deg) translateZ(12px);
    background-color: transparent;
    color: var(--dark);
    font-weight: 700;
}

.overview-trigger:hover .cube-face.back,
.overview-trigger.active .cube-face.back {
    color: var(--black);
}

/* START CLEAN-FIX-P5-S5D-ENCOURAGE-CSS */
/* Accent-colored encouragement pulse on overview-trigger when a project first expands.
   Triggered by JS adding .trigger-encourage class (HomeV3Reference.js EventBus listeners).
   Uses box-shadow (not transform) to coexist with:
     - Existing .module-indicator subtle-pulse (project-column-styles.css line ~2168)
     - idle-cube-rotation below (Phase 5A)
     - typewriter reveal on hover (v3-overview-overlay.css Phase 5A)
   Per-project accent color via CSS variable scoped on column ID.
   Session persistence: removed globally on first overview:opened (JS handler).
   To revert: Delete between START/END markers + CLEAN-FIX-P5-S5D-ENCOURAGE-JS in HomeV3Reference.js */

/* Per-project accent rgb for encouragement pulse */
#project1 .overview-trigger.trigger-encourage { --encourage-rgb: var(--warm-rgb); }
#project2 .overview-trigger.trigger-encourage { --encourage-rgb: var(--blue-rgb); }
#project3 .overview-trigger.trigger-encourage { --encourage-rgb: var(--pink-rgb); }
#project4 .overview-trigger.trigger-encourage { --encourage-rgb: var(--purple-rgb); }
#project5 .overview-trigger.trigger-encourage { --encourage-rgb: var(--darkblue-rgb); }
#project6 .overview-trigger.trigger-encourage { --encourage-rgb: var(--cyan-rgb); }

/* START CLEAN-FIX-P5-S7B0B-ACCENT-RGB-ROOT-HOIST
   :root default for --accent-rgb = --warm-rgb (121, 126, 128).

   Design intent (Pre-7B Gate decision 5, Option C hybrid strategy):
   Unconditional micro-commit shipped BEFORE 7B.2 V1/V7 so the
   token cascades cleanly to:
   - V1 accent gradients outside #projectN descendants (e.g., on
     structural borders that wrap the project columns container)
   - V7 dot matrix on collapsed columns (which may render in DOM
     contexts where the #projectN ancestor selector doesn't match
     because of visual state transitions)
   - M3 scanner sweep inside expanded content (already shipped in
     this file at line 902 via `rgba(var(--accent-rgb, 121, 126,
     128), 0.25)` with hardcoded fallback — this hoist makes the
     fallback redundant but keeps it as defensive code)

   The 7A fallback pattern `rgba(var(--accent-rgb, 121, 126, 128),
   ...)` inlined the default at every consumer site. With --accent-
   rgb now defined at :root, the fallback is redundant but harmless.
   Future consumers (V1, V7, M3) can drop the inline fallback.

   Scope: Defines --accent-rgb at :root with the warm-gray default
   that matches P1's accent (the project that uses --warm, per
   existing #project1 override below). The per-project #projectN
   overrides at CLEAN-FIX-P5-S7A-V3-ACCENT-RGB-TOKEN below this
   block still win for project-descendant elements (ID specificity
   1,0,0 > :root pseudo-class 0,0,1).

   Sibling to 7B.0a (reduced-motion gate) — another unconditional
   micro-commit shipped before 7B.1 structural work for revert-
   safety. Both gates must exist before V7 dot matrix (first new
   visual/motion consumer at 7B.2) ships.

   ─── UPDATE 2026-04-16 — V7 REVERTED ─────────────────────────
   Sub-marker: CLEAN-FIX-P5-S7C2B-M2-V7-REVERT-TRACEABILITY
   V7 dot matrix was subsequently REVERTED at commit 31576bc.
   This gate (the --accent-rgb :root hoist) remains valid for
   all other P5 motion items (V1 accent gradient, M3 scanner
   sweep, M1/M2/M4/M6/M7 AnimationEngine-routed motion, pulse
   variants). No functional change to this block — historical
   context above is preserved for traceability of original
   shipping rationale.
   To revert: Search CLEAN-FIX-P5-S7C2B-M2-V7-REVERT-TRACEABILITY
   and remove this update block. Parent gate is unaffected.
   ─────────────────────────────────────────────────────────────

   Evidence: Option C hybrid strategy decision locked 2026-04-13
   (commit c15f21d Step 0.5 doc update) after tri-review. Code-
   review-analyst explicitly flagged "Hoist --accent-rgb to :root
   with default — prerequisite for V1/V7/M3" as a Pre-7B Gate
   decision requirement. P5-S7A shipped the per-project overrides
   but left :root undefined, creating a cascade gap for consumers
   outside #projectN scope.

   If not effective: (1) Check DevTools computed styles panel for
   any element outside #projectN — should show `--accent-rgb:
   121, 126, 128`. (2) Inside #projectN descendants, should show
   the per-project override values (e.g., `0, 0, 255` for P2).
   (3) Any `var(--accent-rgb, ...)` call-sites should resolve the
   token without needing the inline fallback.

   Verification: No visual change at baseline (both the old
   hardcoded fallback and the new :root default resolve to the same
   warm-gray value). Future V1 gradients will automatically pick
   up the warm-gray default outside #projectN and per-project
   accent inside #projectN.

   To revert: Search CLEAN-FIX-P5-S7B0B-ACCENT-RGB-ROOT-HOIST,
   delete everything between START and END markers. The P5-S7A
   per-project overrides below this block remain untouched. */
:root {
    --accent-rgb: var(--warm-rgb);
}
/* END CLEAN-FIX-P5-S7B0B-ACCENT-RGB-ROOT-HOIST */

/* START CLEAN-FIX-P5-S7A-V3-ACCENT-RGB-TOKEN
   Per-project --accent-rgb token cascade. Set at project root so all descendants
   (.project-subtitle-container, .info-layout-tile, .overview-expanded-container) inherit.
   Pattern mirrors 5D --encourage-rgb precedent (lines above) but at wider scope.
   Reusable by V1 (Phase 7B accent gradients) — single source of truth for accent shadows.
   To revert: Search CLEAN-FIX-P5-S7A-V3-ACCENT-RGB-TOKEN, delete START→END block.
   Note: :root default hoist added above in CLEAN-FIX-P5-S7B0B-ACCENT-RGB-ROOT-HOIST. */
#project1 { --accent-rgb: var(--warm-rgb); }
#project2 { --accent-rgb: var(--blue-rgb); }
#project3 { --accent-rgb: var(--pink-rgb); }
#project4 { --accent-rgb: var(--purple-rgb); }
#project5 { --accent-rgb: var(--darkblue-rgb); }
#project6 { --accent-rgb: var(--cyan-rgb); }
/* END CLEAN-FIX-P5-S7A-V3-ACCENT-RGB-TOKEN */

/* Pulse animation — gated to hover-capable desktop devices */
@media (hover: hover) {
    .overview-trigger.trigger-encourage {
        animation: trigger-encourage-pulse 2.5s var(--easing-concrete, cubic-bezier(0.16, 1, 0.3, 1)) infinite;
    }

    /* Pause pulse on hover so it doesn't fight with the D1 typewriter reveal */
    .overview-trigger.trigger-encourage:hover {
        animation-play-state: paused;
    }
}

@keyframes trigger-encourage-pulse {
    0%, 100% {
        box-shadow: 0 0 0 0 rgba(var(--encourage-rgb, 121, 126, 128), 0);
    }
    50% {
        box-shadow: 0 0 0 6px rgba(var(--encourage-rgb, 121, 126, 128), 0.35);
    }
}
/* END CLEAN-FIX-P5-S5D-ENCOURAGE-CSS */

/* START CLEAN-FIX-P5-S5A-IDLE-ROTATION */
/* D1 Conservative Staggered & Organic — idle cube rotation animation
   Continuous 7s rotation on X-axis. Pauses on hover (cube snaps to back face
   via existing .overview-trigger:hover .cube rule above).
   Gated to (hover: hover) devices to avoid wasted GPU cycles on tablets 820-991
   where users tap instead of hover.
   To revert: Delete between START/END markers */
@media (hover: hover) {
    .overview-trigger:not(:hover):not(.active) .cube {
        animation: idle-cube-rotation 7s ease-in-out infinite;
    }
}

@keyframes idle-cube-rotation {
    0%   { transform: rotateX(0deg); }
    50%  { transform: rotateX(180deg); }
    100% { transform: rotateX(360deg); }
}
/* END CLEAN-FIX-P5-S5A-IDLE-ROTATION */


/* ============================================================================
   START CLEAN-FIX-P5-S6.5c-R4-OVERVIEW-CUBE-AUTOROTATE-UNGATE (2026-04-28)
   ============================================================================
   Universal cube auto-rotation per FINAL design reference.

   Source: test-overview-trigger-animations.html:250-252 (FINAL Implementation
           — title bar of that file). Defines an UNGATED continuous 7s rotation
           on `.overview-trigger .cube` — applies on all viewports, all device
           classes (touch + hover), without any @media wrapper or :not()
           qualifier. The "auto-rotation on nascent interface view" design
           intent: cube is always rotating slowly the moment it appears, the
           ambient motion that draws attention to the CTA.

   Why this chunk: production CLEAN-FIX-P5-S5A-IDLE-ROTATION block above
   (lines 2842-2860) wraps the same animation in @media (hover: hover) AND
   adds :not(:hover):not(.active) qualifications. The (hover: hover) gate
   was added as a touch-device GPU optimization (per the comment at line
   2839) but inadvertently inverts the FINAL design intent — touch tablets
   never get the auto-rotation.

   Per user direction 2026-04-28: apply universally. The FINAL reference's
   design is canonical — auto-rotation everywhere. The (hover: hover)
   optimization is misaligned with the canonical intent.

   Approach: ADD ungated parallel rule (vs MODIFY existing block). Rationale:
   - Atomic-revert isolation (Chunk D reverts independently; CLEAN-FIX-P5-S5A
     stays intact for archaeological clarity).
   - Phase 10.19 cleanup target (also documented in marker comment): delete
     this entire block AND remove the @media (hover: hover) wrapper from
     CLEAN-FIX-P5-S5A-IDLE-ROTATION above. That consolidation simplifies
     the cascade to a single ungated rule matching FINAL reference exactly.

   Cascade behavior:
   - On hover devices: BOTH the gated rule (line 2848) AND this ungated rule
     fire on the same selector. Browsers de-dupe at computed-style stage —
     same animation values produce one keyframe instance, no transition race
     (code-review-analyst confirmed 2026-04-28).
   - On touch devices: only this ungated rule fires (gate doesn't match);
     gap is filled per FINAL design intent.

   Why the :not(:hover):not(.active) qualifier is preserved (vs FINAL
   reference's flat selector): production hover/active rules at lines 2616-2619
   set static `transform: rotateX(180deg)` WITHOUT `animation: none !important`.
   The qualifier prevents the keyframe from competing with the static
   transform. FINAL reference handles this by adding `animation: none
   !important` to its hover rule (line 274 in test-overview-trigger-animations.html);
   we maintain parity with production's existing hover/active static-transform
   convention until Phase 10.19 cleanup aligns the pattern.

   GPU performance: `transform: rotateX(...)` is compositor-promoted; 6
   simultaneous keyframe instances at 7s ease-in-out are negligible on modern
   mobile GPUs (code-review-analyst confirmed 2026-04-28).

   Accessibility paired block: prefers-reduced-motion: reduce stops animation
   for users who opt out of motion (per ui-ninja recommendation 2026-04-28).
   Universal scope (no device-class gate) so reduced-motion respect applies
   to everyone.

   `!important` discipline: ZERO new !important declarations per CLAUDE.md.

   To revert: search CLEAN-FIX-P5-S6.5c-R4-OVERVIEW-CUBE-AUTOROTATE-UNGATE
   and delete everything between START and END markers.
   ============================================================================ */
.overview-trigger:not(:hover):not(.active) .cube {
    animation: idle-cube-rotation 7s ease-in-out infinite;
}

/* Reduced-motion paired block (accessibility — ui-ninja 2026-04-28).
   Universal scope so motion-sensitive users get parity across all devices. */
@media (prefers-reduced-motion: reduce) {
    .overview-trigger .cube {
        animation: none;
    }
}
/* END CLEAN-FIX-P5-S6.5c-R4-OVERVIEW-CUBE-AUTOROTATE-UNGATE */


/* Add other cube faces for complete 3D effect */
.overview-trigger .cube-face.top {
    transform: rotateX(90deg) translateZ(12px);
}

.overview-trigger .cube-face.bottom {
    transform: rotateX(-90deg) translateZ(12px);
}

.overview-trigger .cube-face.left {
    transform: rotateY(-90deg) translateZ(60px);
}

.overview-trigger .cube-face.right {
    transform: rotateY(90deg) translateZ(60px);
}

/* Overview pause button */
.overview-pause-toggle {
    display: none; /* Hidden for now */
    width: 30px;
    height: 24px;
    margin-left: 10px;
    font-size: var(--font-size-small);
    font-weight: 700;
    background-color: transparent;
    border: 1px solid var(--dark);
    border-radius: 2px;
    cursor: pointer;
    align-items: center;
    justify-content: center;
    transition: all var(--transition-fast) ease;
    opacity: 0.6;
}

.overview-pause-toggle:hover {
    opacity: 1;
    background-color: var(--dark);
    color: var(--white);
}

.overview-trigger.active .overview-pause-toggle {
    opacity: 1;
}

/* ========================================
   OVERVIEW MARQUEE STYLES
   ======================================== */

/* Horizontal marquee for projects 2-5 */
.overview-marquee {
    width: 100%;
    overflow: hidden;
    position: relative;
    height: 160px; /* Match the expanded height */
}

/* Animation removed - JavaScript controls scrolling via V3OverviewOverlay component */
.overview-content {
    display: flex;
    /* animation: overview-marquee-scroll 60s linear infinite; */
    width: max-content;
}

/* Animation removed - JavaScript controls all scrolling behavior */
/* .overview-marquee:hover .overview-content {
    animation-play-state: paused;
} */

/* Marquee animation */
@keyframes overview-marquee-scroll {
    0% {
        transform: translateX(0);
    }
    100% {
        transform: translateX(-50%);
    }
}

/* Overview content sections */
.overview-content section {
    padding: 0 40px;
    min-width: 400px;
}

.overview-content h3 {
    font-size: var(--font-size-standard);
    font-weight: 700;
    margin-bottom: 10px;
    text-transform: uppercase;
    letter-spacing: 0.05em;
}

.overview-content p {
    font-size: var(--font-size-small);
    line-height: 1.6;
    color: var(--dark);
    margin-bottom: 15px;
}

/* Vertical marquee for expanded view */
.overview-marquee-vertical {
    height: 100%;
    overflow: hidden;
    position: relative;
}

/* Animation removed - JavaScript controls scrolling via V3OverviewOverlay component */
.overview-marquee-track-vertical {
    /* animation: overview-marquee-scroll-vertical 240s linear infinite; */
}

@keyframes overview-marquee-scroll-vertical {
    0% {
        transform: translateY(0);
    }
    100% {
        transform: translateY(-50%);
    }
}

.overview-content-vertical {
    padding: 20px 0;
}

/* Expanded overview container - COMMENTED OUT to use v3-overview-overlay.css instead */
/*
.overview-expanded-container {
    position: fixed;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    width: 80%;
    max-width: 800px;
    height: 80%;
    max-height: 600px;
    background-color: var(--white);
    border: 2px solid var(--dark);
    box-shadow: 0 10px 30px rgba(0, 0, 0, 0.3);
    z-index: 1000;
    display: flex;
    flex-direction: column;
}

.overview-expanded-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 20px;
    border-bottom: 2px solid var(--dark);
}

.overview-expanded-title {
    font-size: var(--font-size-large);
    font-weight: 700;
    text-transform: uppercase;
}

.overview-pause-toggle-expanded {
    display: none;
    width: 40px;
    height: 40px;
    font-size: var(--font-size-standard);
    font-weight: 700;
    background-color: transparent;
    border: 2px solid var(--dark);
    border-radius: 50%;
    cursor: pointer;
    transition: all var(--transition-fast) ease;
}

.overview-pause-toggle-expanded:hover {
    background-color: var(--dark);
    color: var(--white);
}

.overview-expanded-content {
    flex: 1;
    overflow: hidden;
    padding: 20px;
}
*/

/* ========================================
   PULSE RING ANIMATIONS FOR OVERVIEW
   ======================================== */

.overview-trigger .module-indicator .pulse-ring {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    width: 100%;
    height: 100%;
    border-radius: 50%;
    opacity: 0.5;
}

/* Project-specific pulse colors for overview-trigger */
#project1 .overview-trigger .module-indicator .pulse-ring {
    background-color: rgba(121, 126, 128, 0.5); /* warm */
}

#project2 .overview-trigger .module-indicator .pulse-ring {
    background-color: rgba(0, 0, 255, 0.5); /* blue */
}

#project3 .overview-trigger .module-indicator .pulse-ring {
    background-color: rgba(255, 40, 145, 0.5); /* pink */
}

#project4 .overview-trigger .module-indicator .pulse-ring {
    background-color: rgba(170, 0, 255, 0.5); /* purple */
}

#project5 .overview-trigger .module-indicator .pulse-ring {
    background-color: rgba(7, 7, 51, 0.5); /* darkblue */
}

#project6 .overview-trigger .module-indicator .pulse-ring {
    background-color: rgba(0, 217, 255, 0.5); /* cyan */
}

/* START CLEAN-FIX-P5-S7C2B-M2-SET2-PULSE
   Set 2 tier selection (2026-04-16): Medium M-5 Slow Breathe.

   Element: .overview-trigger .module-indicator .pulse-ring
   Scope: Desktop expanded state (all 6 project columns). Not used on mobile.
   Variation source: test-pulse-variations.html line 203-207 (medium-slow-breathe).
   Tier rationale: Set 1 H-5 Heavy consumed; Set 2 takes one of 2 available
   Medium slots. 3600ms counterpoint cadence provides polyrhythm against
   Set 3's 2400ms and Set 4's 2700ms.

   Replaces: Legacy shared `module-pulse-ring 2s infinite` which was
   duplicated at two definitions (L1170 + this location at ~L2935) and
   cascade-resolved to the same animation for Sets 2 AND 3 (pre-existing
   bug). This commit gives Set 2 its own dedicated keyframe. Set 3 gets
   its own in CLEAN-FIX-P5-S7C2B-M2-SET3-PULSE.

   Keyframe body preserves translate(-50%,-50%) centering transform —
   the .pulse-ring is absolutely positioned and uses this translate for
   center alignment. Removing it would jump the pulse off-center.

   Dependencies: None new. Reads --accent-rgb per-project chain.
   Blocks: Frees legacy module-pulse-ring for removal in Phase 6 streamlining.

   Reversibility: Search CLEAN-FIX-P5-S7C2B-M2-SET2-PULSE, delete between
   START/END markers. Restore `animation: module-pulse-ring 2s infinite`
   on the selector. Legacy keyframe below remains available.

   Verify:
   - XL desktop, expand any project (P1-P6) → overview-trigger pulse-ring
     breathes with scale 1↔1.12 + opacity 0.65↔0.85 over 3600ms.
   - Cycle P1 → P6 → pulse color tracks per-project accent via background-color.
   - prefers-reduced-motion: reduce → animation suppressed (pending C2-6 gate ext).
*/
.overview-trigger .module-indicator .pulse-ring.animate {
    /* R4-PHASE-III-PULSE-REDO 2026-04-28: SET2 M-5 Slow Breathe (set2-overview-slow-breathe 3600ms)
       superseded by S-6 Ambient Glow per Phase II Section 4.5 user-decided pulse mapping.
       Tier 3 Subtle (lowest tier). Source: test-pulse-variations.html line 260. Uses var(--dark-rgb)
       for neutral ambient (deliberate hierarchy choice - NOT per-project accent). Base rule's
       transform: translate(-50%,-50%) preserved (NOT in keyframes; no override). */
    animation: subtle-ambient-glow 5400ms ease-in-out infinite;
}

@keyframes subtle-ambient-glow {
    0%, 100% { box-shadow: 0 0 0 rgba(var(--dark-rgb, 36, 36, 36), 0.2); opacity: 0.35; }
    50%      { box-shadow: 0 0 6px rgba(var(--dark-rgb, 36, 36, 36), 0.3); opacity: 0.55; }
}
/* END CLEAN-FIX-P5-S7C2B-M2-SET2-PULSE */

/* Legacy keyframe retained for revert trace — no consumer after SET2-PULSE
   and SET3-PULSE markers land. Scheduled for removal in Phase 6 streamlining
   (Cluster #1 pulse keyframe unification, see STREAMLINE_OPPORTUNITIES.md). */
@keyframes module-pulse-ring {
    0% {
        transform: translate(-50%, -50%) scale(1);
        opacity: 0.8;
    }
    100% {
        transform: translate(-50%, -50%) scale(3);
        opacity: 0;
    }
}

/* ========================================
   TEMPORARY DEBUG - REMOVE AFTER TESTING
   ======================================== */
/* Force show Project 1's expanded content for styling */
/* Removed forced project1 expansion - let JavaScript control all columns equally */

/* ========================================
   POINTER EVENTS FIX
   ======================================== */
/* Ensure all project column children properly handle pointer events */
.project-column * {
    pointer-events: auto;
}

/* START CLEAN-FIX-P5-S7B1B-V6-BORDER-HAIRLINE
   V6 — LG+ hairline box-shadow on active column (Phase 5 aha, 2026-04-14 scope lock;
   target corrected 2026-04-15 after user visual verification).

   Adds a 1px inset box-shadow on `.project-column.active .project-expanded`
   at LG+ (`@media (min-width: 992px)`), in the per-project accent color at
   0.35 alpha. Provides a subtle structural outline on the active column's
   visible surface — a hairline silhouette in the accent color that traces
   the trapezoid shape.

   Target correction (2026-04-15):
   The first attempt applied the inset shadow to `.project-column.active`
   directly. That was invisible because `.project-column .project-expanded`
   (defined at line 810) is `position: absolute; top: 0; left: 0; width: 100%;
   height: 100%; background-color: var(--white); z-index: 10` — a
   solid-white absolutely-positioned child that fills the parent and
   visually occludes the parent's inset shadow entirely. `.project-expanded`
   is the actual visible surface at LG+ when the column is active (per user
   note: "project column's (desktop implementation) are granted
   class='project-expanded'"), so the paint target has to be the child.

   Why this still traces the trapezoid shape:
   `.project-expanded` itself has NO clip-path, so its border-box is a
   rectangle (100% × 100% of the parent). A raw inset shadow on a rectangle
   would paint as a rectangle — BUT the parent `.project-column` has
   `clip-path: polygon(2% 0, 98% 0, 100% 100%, 0% 100%)` at line 190, and
   clip-path on a parent clips ALL child rendering including the child's
   box-shadow. So the rectangular inset shadow painted inside
   `.project-expanded`'s border-box gets clipped to the parent polygon at
   render time, and what you actually see is the trapezoid silhouette.
   (Rectangle shadow ∩ parent polygon = trapezoid hairline.)

   Why inset box-shadow (not `border`):
   Even if we put a real `border` on `.project-expanded`, the border-box
   would be rectangular and the parent polygon would clip only the
   overlapping edges — you'd see four rectangular border segments with two
   diagonal gaps where the polygon cut the corners. Inset shadow paints as
   a continuous rectangle that's fully clipped to the polygon, giving a
   single unbroken trapezoid edge. That's the Brutalist-coherent look.

   Outline (`outline:`) was considered and rejected — it's rendered outside
   the border-box, not clipped by the parent polygon, and would sit as a
   rectangular frame around the trapezoid. Wrong aesthetic.

   Color source:
   `rgba(var(--accent-rgb), 0.35)` — consumes the per-project `--accent-rgb`
   token cascaded from `:root` via the 7B.0b hoist (project-column-styles.css
   line 2546) with per-project overrides at lines 2558–2562. Hairline color
   tracks P1 warm / P2 blue / P3 pink / P4 purple / P5 darkblue / P6 cyan.
   Hardcoded `121, 126, 128` fallback retained for defensive-read safety
   (matches --warm default). Phase 9 cleanup item: remove the inline fallback
   now that :root hoist makes it redundant.

   Top + bottom border pivot (2026-04-15 user visual call):
   The previous iteration used `box-shadow: inset 0 0 0 2px …` to trace
   the parent polygon as a full 4-sided trapezoid hairline. Two things
   changed:
   1. The active desktop column polygon was removed (identity polygon
      via CLEAN-FIX-P5-S7BX-ACTIVE-CLIP-PATH-NONE below) so the inset
      shadow no longer traced a trapezoid — it was rendering as a
      rectangular ring around the active column.
   2. User visual call: the 4-sided rectangle ring read as "frame
      around a TV" rather than as structural architecture. Asked for
      top + bottom only, asymmetric alpha, no left/right borders —
      a classic Brutalist "ceiling beam + floor shadow" horizontal
      banding that frames the active column without boxing it in.

   Pivot to `border-top` + `border-bottom` on the active
   `.project-expanded` child:
   - Top border at 0.72α (12×6n compliant) — heavier, reads as ceiling
     beam anchoring the active column's upper edge
   - Bottom border at 0.36α (6×6n compliant) — half-weight, reads as
     floor shadow grounding the column's lower edge
   - No left/right border — the vertical dimension stays open, columns
     breathe sideways against the collapsed neighbors
   - `box-sizing: border-box` set explicitly so the 2px borders don't
     bleed beyond the parent's 100%×100% absolute positioning bounds

   6n alpha tier rationale:
   Both 72 and 36 are 6n multiples (12×6 and 6×6 respectively), honoring
   the v3 design system's 6n tier even for sub-unit values like opacity
   percentages. This is a consistency decision — while opacity doesn't
   strictly map to pixel tiers, choosing values from the 6n family keeps
   the mental model clean (all measurements in the project, including
   visual weight percentages, resolve to 6n tiers). Non-6n values like
   0.80 / 0.40 were the first draft; rejected during commit review to
   preserve theme consistency.

   Single media tier (not LG/XL split):
   Unlike the previous box-shadow version which scaled alpha 0.28 →
   0.35 across LG → XL to compensate for stroke-to-canvas ratio, the
   top+bottom border pair doesn't need tiered opacity because borders
   are crisp-edge rendering (not soft shadow synthesis) and the alpha
   scaling logic was specific to filled strokes on trapezoids. One
   media block covers LG + XL cleanly.

   No more stroke-weight normalization:
   The previous two-tier opacity scale (LG 0.28 / XL 0.35) was a
   "stroke weight normalization" pattern where alpha compensated for
   stroke-to-canvas ratio differences. For a top+bottom horizontal
   band, the ratio dynamics are different — horizontal bands scale
   symmetrically with viewport width so alpha doesn't need to
   compensate. Dropped to a single media tier.

   LG+ gate (not XL-only):
   The hairline is a structural outline, not a decorative motion layer, so
   it gates at LG (992px) where the expanded column has enough horizontal
   breathing room to make the outline read as structure. Tighter XL-only
   gating was considered but rejected — LG users get the same expanded
   state and deserve the same structural read.

   Dependencies: 7B.0b `--accent-rgb` :root hoist (LANDED at 388da45).
   Blocks: Nothing downstream depends on V6.

   Reversibility: Search CLEAN-FIX-P5-S7B1B-V6-BORDER-HAIRLINE and delete
   everything between START and END markers. Single file, two media blocks.

   Verify:
   - 992×700 (LG min) → 2px colored hairline at 0.28α tracing the trapezoid
     edge of the active column. Feels structural, not chunky.
   - 1199×800 (LG max) → still at 0.28α (LG tier).
   - 1200×800 (XL min) / 1920×1080 (XL wide) → 2px hairline at 0.35α —
     slightly more present to compensate for wider canvas.
   - 991×1200 (MD max) → NO hairline (gate cuts off at 992px).
   - Cycle P1 → P6 on any of the above viewports → hairline color tracks
     per-project accent (warm / blue / pink / purple / darkblue / cyan).
   - DevTools → Rendering → Emulate prefers-reduced-motion: reduce →
     hairline unchanged (it's static, not animated, so reduced-motion is
     a no-op here, which is correct).

   Verification surface: `test-responsive-production.html` viewport frames
   OR `index.html` directly. NOT `test-v8-gateway-harness.html` (reference
   code, not production — see reference_test_responsive_production.md). */
@media (min-width: 992px) {
    .project-column.active .project-expanded {
        box-sizing: border-box;
        border-top: 2px solid rgba(var(--accent-rgb, 121, 126, 128), 0.36);
        border-bottom: 2px solid rgba(var(--accent-rgb, 121, 126, 128), 0.18);
    }
}
/* END CLEAN-FIX-P5-S7B1B-V6-BORDER-HAIRLINE */

/* START CLEAN-FIX-P5-S7B2A-V1-ACCENT-GRADIENT
   V1 — XL accent gradient on active column's .project-header (Phase 5 aha,
   2026-04-14 scope lock).

   Adds a radial-gradient bleed to `.project-column.active .project-header`
   at XL only (`@media (min-width: 1200px)`) — a soft per-project accent
   color fading from the top of the header box down into the info column.
   At 0.08 alpha → transparent, the effect reads as "the active project's
   identity subtly saturating its own header region" rather than as a
   decorative frame.

   Target choice (.project-header, NOT .project-subtitle-container):
   `.project-subtitle-container` at line 888 has its own clip-path
   (`polygon(1% 0, 100% 0, 100% 100%, 0% 100%)`) — a gradient on it would
   be clipped to the polygon edge and read as a sharp-edged swatch,
   fighting the subtle-bleed intent. `.project-header` at line 1375 has
   NO clip-path and NO existing background — it's a clean paint surface
   and its parent `.project-expanded` has `background-color: var(--white)`
   so the gradient reads against a solid white base exactly as designed.

   Why radial, not linear:
   Linear-gradient(to bottom, ...) would produce a horizontal band of
   color that reads as a highlighted strip, conflicting with the V6
   hairline trapezoid trace (Commit 12). Radial-gradient(ellipse at top)
   produces a soft dome of color from the top-center fading outward and
   downward, which reads as ambient tint rather than as a structural
   element — the Brutalist "weight without decoration" call.

   Ellipse at top (vs circle at top):
   Ellipse shapes the bleed to the header's flex aspect ratio, so wide
   headers get a wide bleed and tall headers get a tall bleed. Circle
   would produce a fixed-aspect bleed that reads as a spot at the top of
   wide headers — aesthetically off.

   0.04 alpha (halved from initial 0.08 after 2026-04-15 visual review):
   Starting 0.08 (below the 0.1 "ACCEPTED" ceiling) read as "visible
   decoration" rather than "quiet ambient character." User call after
   first-pass shipping: halve the alpha so the bleed is "you notice it
   if you look for it, once" not "you notice it every time." V6 at
   0.28–0.35α is the eye-catch; V1 at 0.04α is ambient tint underneath
   that rewards close inspection without competing for attention.

   60% transparent stop:
   Gradient reaches 0α at 60% of the radius, so the bottom 40% of the
   header (and everything below) is pure parent background. Prevents
   the bleed from extending into the subtitle container (which has its
   own V3 accent shadow from 7A commit, line 902).

   XL-only gate:
   V1 is purely decorative and the bleed needs horizontal breathing room
   to read as ambient rather than as a band. XL (1200px+) gives the
   active column ≥1150px width at 1200×800 and ≥1800px at 1920×1080,
   where the gradient has room to feel spacious. LG (992–1199px) would
   compress the bleed into a tighter space where it reads as a strip.

   Color source:
   `rgba(var(--accent-rgb), 0.08)` — consumes the per-project `--accent-rgb`
   token cascaded from `:root` via the 7B.0b hoist (project-column-styles.css
   line 2546) with per-project overrides at lines 2558–2562. Bleed color
   tracks P1 warm / P2 blue / P3 pink / P4 purple / P5 darkblue / P6 cyan.
   Hardcoded `121, 126, 128` fallback retained for defensive-read safety.
   Phase 9 cleanup item: remove the inline fallback now that :root hoist
   makes it redundant.

   Dependencies: 7B.0b `--accent-rgb` :root hoist (LANDED at 388da45).
   Stacking with V6 (Commit 12, shipped aa46b53): V6's inset box-shadow
   lives on `.project-expanded`; V1's gradient lives on `.project-header`
   which is a descendant of `.project-expanded`. The two paint layers
   don't overlap — V6 traces the outer polygon edge, V1 tints the
   header region. No z-index conflict, no paint order issue.

   Reversibility: Search CLEAN-FIX-P5-S7B2A-V1-ACCENT-GRADIENT and
   delete everything between START and END markers. Single file, single
   rule. Fully revertable via `git revert <sha>`.

   Verify:
   - 1200×800 (XL min) → subtle per-project color dome at top of active
     column's header region, fading to transparent by mid-header height.
     V6 hairline still visible as outer edge (no conflict).
   - 1920×1080 (XL wide) → bleed spreads wider; still reads as ambient
     not as band.
   - 1199×800 (LG max) → NO gradient (gate cuts off at 1200px).
   - 991×1200 (MD max) / 992×700 (LG min) → NO gradient.
   - Cycle P1 → P6 at 1200×800 → bleed color tracks per-project accent.
   - DevTools → Rendering → Emulate prefers-reduced-motion: reduce →
     gradient unchanged (static paint, not animated — correct no-op).

   Verification surface: `test-responsive-production.html` viewport frames
   OR `index.html` directly. NOT `test-v8-gateway-harness.html` (reference
   code, not production — see reference_test_responsive_production.md). */
@media (min-width: 1200px) {
    .project-column.active .project-header {
        background: radial-gradient(
            ellipse at top,
            rgba(var(--accent-rgb, 121, 126, 128), 0.04) 0%,
            transparent 60%
        );
    }
}
/* END CLEAN-FIX-P5-S7B2A-V1-ACCENT-GRADIENT */

/* START CLEAN-FIX-P5-S7BX-ACTIVE-CLIP-PATH-NONE
   Remove `.project-column` polygon clip-path on active desktop columns.

   Context: The base `.project-column` rule at line 190 sets
   `clip-path: polygon(2% 0, 98% 0, 100% 100%, 0% 100%)` — the trapezoid
   shape. That shape is visually meaningful on COLLAPSED desktop columns
   (where the column fills its slot with `background-color: var(--light)`
   and the polygon frames the background as an angular concrete slab).

   On ACTIVE desktop columns, the polygon is problematic:
   - `.project-header` content (coord-lines at absolute (21, 42),
     `.project-number` at absolute (24, 48)) sits right at the polygon's
     top-left diagonal boundary (at y=0 the polygon cuts x=0..2% of the
     column width, which is ~23px at 1920 viewport). This clips the
     coord-line left-end and visually shaves the "4D°"-style project
     number.
   - The active expanded view fills the entire column with content
     (info panel on left, mockups on right), so the trapezoid shape has
     no structural purpose — it's just a corner cut that breaks content.

   User call 2026-04-15: "At some point a clip-path was added to
   project-column active in desktop project column implementation. This
   is incorrect as clip-path would only be visually relevant on
   collapsed project columns (with a background color) for the desktop
   project column implementation. Remove clip-path shape on
   project-column active values where we can."

   Historical context (from backups/2025-11-06_issues-overview-accent-lines.txt):
   A previous attempt shipped `.project-column.active { clip-path: none
   !important; }` which was rolled back and narrowed to
   `.project-column.active:has(.process-overlay-dark) { clip-path: none
   !important; }` (at v3-overview-overlay.css:72-75) because the broad
   rule was affecting overlay rendering in a way that wasn't the target
   at the time. The current user request addresses a DIFFERENT concern
   (content clipping, not overlay handling), so the broader scope is
   correct here — the narrower `:has()` rule still stays in place as a
   redundant safety net, to be cleaned up in Phase 9 once this has
   soaked.

   Why identity polygon (not `clip-path: none`):
   `.project-column.concrete-collapse` at line 525 transitions clip-path
   during collapse. Transitioning from `clip-path: none` to a polygon
   is inconsistent across browsers — Chromium animates "discretely"
   (snaps to final), Firefox skips, Safari does mixed. Using the
   identity polygon `polygon(0 0, 100% 0, 100% 100%, 0 100%)` keeps
   the transition polygon-to-polygon which all browsers interpolate
   smoothly. Identity polygon is effectively "no clipping" (the shape
   is the full rectangle) while preserving animatability.

   Why min-width: 820px (not 992px):
   820px is the breakpoint where C.8-C.11 project columns shift to
   desktop 6-column layout (per P5-S3-BREAKPOINT-820 in the responsive
   file). At that point forward, the column is considered "desktop
   implementation" and the polygon is no longer structurally needed on
   active. Mobile carousel mode (<820px) keeps default behavior.

   V6 hairline side effect acknowledged:
   V6 (`CLEAN-FIX-P5-S7B1B-V6-BORDER-HAIRLINE` above) applies an inset
   box-shadow on `.project-column.active .project-expanded` that
   previously traced the parent polygon to render a trapezoid hairline.
   With the identity polygon on active, V6 becomes a rectangular inset
   shadow. This is an accepted aesthetic tradeoff — the rectangular
   active column reads as "structural anchor" against the 5 trapezoid
   collapsed columns, creating visual hierarchy via shape difference.
   V6 still provides the per-project accent outline; the shape just
   changes from trapezoid to rectangle.

   Stacking with existing overlay clip-path removal:
   `v3-overview-overlay.css:72-75` has
   `.project-column.active:has(.process-overlay-dark),
    .project-column.active:has(.no-scroll-needed) {
       clip-path: none !important;
    }`
   That rule becomes redundant (the broader rule here already removes
   the effective clip on all active columns). Left in place for
   revert safety — can be cleaned up in Phase 9 once this commit
   has soaked.

   Dependencies: None.
   Blocks: Nothing downstream depends on active column clip-path.

   Reversibility: Search CLEAN-FIX-P5-S7BX-ACTIVE-CLIP-PATH-NONE and
   delete everything between START and END markers. Single file, single
   rule.

   Verify:
   - 820×700 and up: active column's project-header shows coord-line
     and project-number rendering in full at the top-left corner (no
     clipping on the left edge of the coord-line or number).
   - Collapsed columns at any width: still trapezoidal (this rule
     only targets `.project-column.active`, not the base).
   - Transition from active → collapsed (click a different column):
     polygon animates smoothly from identity to (2% 0, 98% 0, 100% 100%, 0% 100%).
   - V6 hairline still visible but now rectangular (inset shadow
     follows rectangle, not trapezoid) on the active column.
   - 600×800 (SM): base `.project-column { clip-path: none }` from
     `@media (max-width: 767px)` at project-column-styles.css:795 wins
     (mobile carousel mode unaffected).

   Verification surface: `test-responsive-production.html` or
   `index.html` directly. NOT `test-v8-gateway-harness.html`. */
@media (min-width: 820px) {
    .project-column.active {
        clip-path: polygon(0 0, 100% 0, 100% 100%, 0 100%);
    }
}
/* END CLEAN-FIX-P5-S7BX-ACTIVE-CLIP-PATH-NONE */

/* START CLEAN-FIX-P5-S7C2-M1-MOMENTUM-FLEX
   M1 — XL momentum flex transition on project columns (Phase 5 aha,
   2026-04-14 scope lock — pure CSS, not AnimationEngine).

   Overrides the existing `.project-column { transition: flex 0.45s
   cubic-bezier(0.22, 1, 0.36, 1), ... }` (line 182) at XL only with
   an EXTENDED duration (0.45s → 0.55s) using the same concrete curve.
   The longer duration adds perceptible *weight* to column expansion
   — active column expansion feels heavier, like a concrete block
   sliding into place — without introducing bounce or overshoot.

   Decision history (ui-ninja + code-review + Plan agent review trail):
   The first-pass plan called for a back-ease overshoot curve
   `cubic-bezier(0.34, 1.56, 0.64, 1)` — a bounce-ish settling motion.
   ui-ninja review flagged this as tonally playful/elastic, inconsistent
   with Brutalist restraint ("weight in motion, not decoration").
   Locked during 2026-04-14 Step 0 sync to pure concrete curve with
   extended duration — same curve as the base rule but stretched to
   0.55s so the motion has more perceptible heft without overshoot.

   Why pure CSS (not AnimationEngine.tween):
   No velocity state exists in the current column system to drive an
   engine tween. "Momentum" in the physics sense requires input (prior
   velocity, mass) that doesn't exist here — there's no carry-over
   between gestures. The CSS cubic-bezier handles the visual weight
   effect perfectly at zero JS cost, and honors `prefers-reduced-motion`
   natively via the paired media rule below.

   Specificity raise (`.projects-container > `):
   `.project-column.concrete-collapse` at `v3-project-columns-
   responsive.css:525–529` fully specifies `transition: flex ...`
   with equal specificity (two classes) but LATER source order than
   the base `.project-column` rule. A plain `@media (min-width: 1200px)
   .project-column { transition: ... }` at (0,1,0) would be beaten by
   concrete-collapse at (0,2,0) whenever the JS toggles that class for
   collapse animations.

   Solution: use `.projects-container > .project-column:not(.concrete-
   collapse)` which lands at (0,3,0) specificity:
     - .projects-container (0,1,0)
     - .project-column      (0,1,0)
     - :not(.concrete-collapse) — counts its argument (0,1,0)
     = (0,3,0) total
   This beats concrete-collapse at (0,2,0) AND explicitly excludes
   the concrete-collapse state via the :not() so the collapse animation
   keeps its own curve (JS-driven 480ms collapse curve wins during that
   window).

   Reduced-motion mirror rule:
   Paired `@media (min-width: 1200px) and (prefers-reduced-motion:
   reduce)` block collapses the transition to `flex 0.2s linear` —
   short, linear, no ease. Uses the same `.projects-container >` prefix
   for specificity parity (Plan-agent amendment from Step 0 sync —
   without the prefix, the reduced-motion rule would lose to the
   motion rule at equal specificity but earlier source order).

   Side effect acknowledged — hover overshoot:
   `.project-column:hover:not(.active) { flex: 0.96 }` at line 210
   uses the column's transition property for hover shrink. With the
   new 0.55s curve at XL, hover response also feels heavier. This is
   desirable for weight-in-motion philosophy (hover should feel
   deliberate, not flippant) and is noted here so a future reviewer
   knows it's intentional, not a surprise.

   XL-only gate:
   Active column expansion is visible enough to benefit from the
   weight effect only when the column is wide (≥1150px at 1200×800,
   ≥1800px at 1920×1080). At LG (992–1199) the active column is
   narrower and the 0.55s duration feels sluggish. At MD and below
   the mobile carousel mode doesn't use flex transitions at all.

   Dependencies: None (purely a transition override).
   Blocks: Nothing downstream.

   Reversibility: Search CLEAN-FIX-P5-S7C2-M1-MOMENTUM-FLEX and delete
   everything between START and END markers. Single file, two media
   blocks (one for the main rule, one for reduced-motion mirror).

   Verify:
   - 1200×800 (XL min) and 1920×1080 (XL wide): click between projects,
     active column expansion feels heavier, longer settle compared to
     the base 0.45s at LG/MD.
   - 1199×800 (LG max): original 0.45s base transition applies, no
     change from pre-M1 behavior.
   - Hover a non-active column at XL: the 0.96 flex shrink uses the
     new 0.55s curve (intentional — heavier hover read).
   - JS-driven collapse (clicking away from an active column): the
     .concrete-collapse class temporarily applies during collapse,
     concrete-collapse's own 480ms curve wins (because M1's :not()
     excludes it), then concrete-collapse is removed and M1 returns.
   - DevTools → Rendering → Emulate prefers-reduced-motion: reduce →
     transition drops to 0.2s linear, no weight effect, no overshoot.

   Verification surface: `test-responsive-production.html` or
   `index.html` directly. NOT `test-v8-gateway-harness.html`. */
@media (min-width: 1200px) {
    .projects-container > .project-column:not(.concrete-collapse) {
        transition: flex 0.55s cubic-bezier(0.22, 1, 0.36, 1),
                    background-color 0.4s ease,
                    clip-path 0.55s cubic-bezier(0.22, 1, 0.36, 1),
                    z-index 0s linear;
    }
}
@media (min-width: 1200px) and (prefers-reduced-motion: reduce) {
    .projects-container > .project-column:not(.concrete-collapse) {
        transition: flex 0.2s linear, background-color 0.2s ease, clip-path 0.2s linear, z-index 0s linear;
    }
}
/* END CLEAN-FIX-P5-S7C2-M1-MOMENTUM-FLEX */

/* START CLEAN-FIX-P5-S7C2-COLUMN-TRANSITION-SMOOTHING
   Smooth clip-path transitions across all desktop project columns to
   eliminate jerky expand/collapse on P1/P6 (Phase 5, 2026-04-15 user
   visual verification during M1 commit review).

   Problem surfaced during M1 (Commit 16 7b39ae5) verification:
   User reported P1 ("HI!" project) still expanding/collapsing with
   visible jerkiness compared to other projects, despite M1's smooth
   flex curve working correctly. Goal: make ALL project column
   expand/collapse as smooth/consistent as possible on desktop.

   Root cause diagnosed:
   The base `.project-column` transition at line 182 lists only
   `flex`, `background-color`, and `z-index` — NOT `clip-path`.
   So when `.active` is toggled, any clip-path change happens
   INSTANTLY (no transition to animate the shape morph).

   For P2-P5: trapezoid polygon (2% 0, 98% 0, ...) → identity
   polygon (0 0, 100% 0, ...) via CLEAN-FIX-P5-S7BX-ACTIVE-CLIP-PATH-
   NONE (b46b6d6). The 2% corner cut vanishes instantly — a small
   visual snap but barely noticeable because both values are valid
   4-point polygons of similar shape.

   For P1/P6: two additional systems kick in on `.no-scroll-needed`
   overlays (the pentagon-shape small overlays P1/P6 use):
     - CSS `:has()` rule at v3-overview-overlay.css:72-75 sets
       `clip-path: none !important` to prevent compound clipping
     - JS imperative at V3OverviewOverlay.js:575-587 sets
       `style.clipPath = 'none'` directly on the column element
   Both end up with `clip-path: none`, which is NOT a polygon.

   Browsers cannot interpolate `clip-path: polygon(...)` to
   `clip-path: none` — the value types are different. Transitions
   involving `none` snap to the final value instead of animating.
   This causes visible jerks on P1/P6 expand (trapezoid → none snap)
   and collapse (none → trapezoid snap).

   Fix applied across 4 places (all under this same marker):

   1. THIS BLOCK — new media rule at `@media (min-width: 820px)`
      adding `clip-path 0.45s cubic-bezier(0.22, 1, 0.36, 1)` to the
      base `.project-column` transition at desktop only. Scoped to
      820+ (not the base rule itself) to avoid mobile resize jank
      between polygon (desktop) ↔ none (SM and below at line 795).

   2. M1 XL rule above (extended by this commit) — added matching
      `clip-path 0.55s` to keep clip-path synchronized with the flex
      transition at XL. Paired reduced-motion mirror also extended
      with `clip-path 0.2s linear`.

   3. `v3-overview-overlay.css:72-75` — updated `clip-path: none
      !important` to `clip-path: polygon(0 0, 100% 0, 100% 100%, 0 100%)
      !important`. Functionally identical (identity polygon = no
      effective clipping) but a valid polygon that transitions
      smoothly with the collapsed trapezoid.

   4. `V3OverviewOverlay.js:575-587` and `:874-888` — updated
      imperative JS manipulation from `style.clipPath = 'none'` to
      the identity polygon string. Restoration logic unchanged
      (still clears inline style on collapse).

   Why identity polygon instead of removing the `none` mechanism:
   The `:has()` rule and JS manipulation were added to fix a real
   compound-clipping issue on pentagon overlays. The fix still
   needs to remove effective clipping on the parent while allowing
   smooth transitions. Identity polygon `polygon(0 0, 100% 0,
   100% 100%, 0 100%)` satisfies both:
     - No effective clipping (the polygon is the full rectangle)
     - Valid polygon value that interpolates with the trapezoid

   Asymmetric transition durations preserved:
   - MD/LG (820-1199): base transition 0.45s — matches existing
     curve timing
   - XL (1200+): M1 transition 0.55s — matches M1's extended
     concrete curve for added weight
   - Concrete-collapse (JS-driven collapse): 480ms concrete curve
     (existing rule at v3-project-columns-responsive.css:525-529
     already includes clip-path in its transition list, unchanged)
   All three paths now have smooth polygon → polygon transitions.

   V6 side effect (neutral-to-positive):
   V6 border-top/bottom on `.project-column.active .project-expanded`
   renders as a rectangle clipped by the parent's clip-path. During
   the new shape morph transition, the V6 border corners are briefly
   clipped by the parent's diagonal (when transitioning between
   trapezoid and identity polygon). This creates a subtle "border
   emerging from behind the trapezoid corners" effect on expand and
   "border retracting into the trapezoid corners" on collapse —
   visually harmonious with the shape morph.

   Dependencies: CLEAN-FIX-P5-S7BX-ACTIVE-CLIP-PATH-NONE (b46b6d6,
   identity polygon on active) — this smoothing commit builds on
   top of it by animating the shape morph instead of snapping.

   Reversibility: Search CLEAN-FIX-P5-S7C2-COLUMN-TRANSITION-SMOOTHING
   and delete everything between START and END markers. Also requires
   reverting the 3 paired changes in the other 2 files under the same
   marker (v3-overview-overlay.css `:has()` rule and V3OverviewOverlay.js
   imperative). Full `git revert <sha>` of this commit handles all 4
   changes atomically.

   Verify:
   - P1/P6 expand at XL: smooth shape morph (no instant snap), flex
     and clip-path transition synchronized over 0.55s
   - P2-P5 expand at XL: similar smooth morph (previously instant,
     now subtle)
   - All projects expand at LG/MD (820-1199): smooth morph at 0.45s
   - All projects collapse at any desktop width: concrete-collapse
     path unchanged, smooth
   - Hover shrink on non-active columns at XL: flex and clip-path
     both use the 0.55s curve (clip-path doesn't change on hover,
     so this doesn't manifest visibly, but transition declaration
     is consistent)
   - Reduced-motion: clip-path drops to 0.2s linear at XL, no curve

   Verification surface: `test-responsive-production.html` or
   `index.html` directly. */
@media (min-width: 820px) {
    .project-column {
        transition: flex 0.45s cubic-bezier(0.22, 1, 0.36, 1),
                    background-color 0.4s ease,
                    clip-path 0.45s cubic-bezier(0.22, 1, 0.36, 1),
                    z-index 0s linear;
    }
}
@media (min-width: 820px) and (prefers-reduced-motion: reduce) {
    .project-column {
        transition: flex 0.2s linear, background-color 0.2s ease, clip-path 0.2s linear, z-index 0s linear;
    }
}
/* END CLEAN-FIX-P5-S7C2-COLUMN-TRANSITION-SMOOTHING */


/* ============================================================================
   START CLEAN-FIX-VI-B1-P1-CTA-3C-DECORATION-STRIP-MINIMAL (2026-05-07)
   ============================================================================
   P1 case-study-cta — '3C Decoration Strip Minimal' port from
   test-lg-element-variations.html lines 522-569 (USER-PICKED variation).

   This fence COMPANIONS the LG-MACRO-E-P1 modify-in-place at
   v3-project-columns-responsive.css:4029+. LG-MACRO-E-P1 fires at
   `(820-1424 × ≤800h)` with !important — it WINS cascade at LG-short
   composites. This fence covers the rest of larger-implementation viewports
   where LG-MACRO-E-P1 doesn't fire: MD-larger × >800h, LG-tall × >800h,
   XL-tall × >800h, XL-wide >1424. Both fences carry IDENTICAL 3C chrome
   values so cascade outcome is consistent regardless of which wins.

   Specificity discipline: chain is
   `.project-column[data-index="1"] .project-info-column .case-study-cta
    .view-case-btn .{cta-module|module-indicator|pulse-ring|cube-wrapper}`
   (0,5,1) — wins cleanly over baseline rules at lines 1099 (.cta-module 0,1,1),
   1123 (.module-indicator 0,1,1), 1158 (.pulse-ring 0,1,2), 1243 (.cube-wrapper).
   ZERO new !important — relies on selector chain depth.

   Per-project accent retained via existing line 1135 rule
   (`#project1 .view-case-btn .module-indicator { background-color: var(--warm) }`).

   Pulse animation keyframe retained via CLEAN-FIX-P5-S7C2B-M2-SET3-PULSE
   at line 1169 — DO NOT modify (load-bearing per existing fence).

   Cube rotation retained — production .cube / .cube-face.front / .cube-face.back
   rules at lines 583+ handle 3D rotation; .view-case-btn:hover .cube transform
   trigger at line 1249 unchanged.

   Scope: (min-width: 768px) covers MD-larger / LG / XL per user direction
   "larger-implementation project columns."

   To revert: search CLEAN-FIX-VI-B1-P1-CTA-3C-DECORATION-STRIP-MINIMAL and
   delete between START and END markers. Also revert modify-in-place edits
   inside CLEAN-FIX-P5-S6.5c-A3-LG-MACRO-E-P1 (look for 'VI-B1' inline tags).
   ============================================================================ */
@media (min-width: 768px) {
    .project-column[data-index="1"] .project-info-column .case-study-cta {
        width: 100%;
    }
    .project-column[data-index="1"] .project-info-column .case-study-cta .view-case-btn {
        padding: 6px 0;
        background-color: transparent;
        border: none;
        width: 100%;
        height: 42px;
        color: var(--dark);
        display: flex;
        flex-direction: row;
        align-items: center;
        gap: 12px;
        justify-content: flex-start;
    }
    .project-column[data-index="1"] .project-info-column .case-study-cta .view-case-btn .cta-module {
        width: 24px;
        height: 24px;
        border: none;
        background-color: transparent;
        display: block;
        position: relative;
        flex-shrink: 0;
    }
    .project-column[data-index="1"] .project-info-column .case-study-cta .view-case-btn .module-indicator {
        width: 8px;
        height: 8px;
        position: absolute;
        top: 8px;
        left: 8px;
        margin: 0;
        opacity: 1;
    }
    .project-column[data-index="1"] .project-info-column .case-study-cta .view-case-btn .module-indicator .pulse-ring {
        width: 16px;
        height: 16px;
        top: 50%;
        left: 50%;
        transform: translate(-50%, -50%);
        border: 1px solid var(--warm);
        background-color: transparent;
        opacity: 0.5;
    }
    .project-column[data-index="1"] .project-info-column .case-study-cta .view-case-btn .cube-wrapper {
        width: 140px;
        height: 24px;
        perspective: 600px;
        transform-style: flat;
        overflow: hidden;
        position: relative;
        background: transparent;
        margin-left: 12px;
        flex-grow: 0;
        display: block;
    }

    /* === VI-B2-M4B-BRACKETS-M4D-HOVER (modify-in-place 2026-05-11) ===========
       M4B (default state): corner brackets ⌐ (top-left 12×12) + ⌙ (bottom-right
       12×12) via ::before + ::after pseudo-elements. Both border-color pulse
       warm ↔ lightest at 2.5s ease-in-out infinite (keyframe p1-cta-m4b-bracket-
       pulse in timeline-components-rebuilt.css).
       M4D (hover state): dual-weight inset box-shadow (1px top + 2px bottom warm)
       appears on :hover; smooth entry via `transition: box-shadow 200ms ease-out`.
       Persists during the existing 800ms hoverDelay until overview overlay opens
       (V3OverviewOverlay.js:707-810 — mouseenter → expandOverlay chain unchanged).
       Architecture per 3-agent Stage 4 review 2026-05-11. ZERO new !important at
       this scope (specificity 0,5,1+ chain depth wins via source order). Mirrored
       with !important in LG-MACRO-E-P1 fence at v3-project-columns-responsive.css
       L4036-4099 for the (820-1424 × ≤800h) compressed-mode composite per L8
       cascade-add discipline.
       To revert M4B+M4D additions only: delete from `/* === VI-B2-M4B-BRACKETS-
       M4D-HOVER` through this rule's closing `}`. ZERO impact on 3C base. */
    .project-column[data-index="1"] .project-info-column .case-study-cta .view-case-btn {
        transition: box-shadow 200ms ease-out;
    }
    .project-column[data-index="1"] .project-info-column .case-study-cta .view-case-btn::before {
        content: '';
        position: absolute;
        top: 0;
        left: 0;
        width: 12px;
        height: 12px;
        border-top: 2px solid rgb(var(--warm-rgb));
        border-left: 2px solid rgb(var(--warm-rgb));
        pointer-events: none;
        animation: p1-cta-m4b-bracket-pulse 2.5s ease-in-out infinite;
    }
    .project-column[data-index="1"] .project-info-column .case-study-cta .view-case-btn::after {
        content: '';
        position: absolute;
        bottom: 0;
        right: 0;
        width: 12px;
        height: 12px;
        border-bottom: 2px solid rgb(var(--warm-rgb));
        border-right: 2px solid rgb(var(--warm-rgb));
        pointer-events: none;
        animation: p1-cta-m4b-bracket-pulse 2.5s ease-in-out infinite;
    }
    .project-column[data-index="1"] .project-info-column .case-study-cta .view-case-btn:hover {
        box-shadow: inset 0 1px 0 0 rgb(var(--warm-rgb)), inset 0 -2px 0 0 rgb(var(--warm-rgb));
    }
}
/* END CLEAN-FIX-VI-B1-P1-CTA-3C-DECORATION-STRIP-MINIMAL */

/* START CLEAN-FIX-P5-SESSION7-P1CTA-M4B-M4D-REDUCED-MOTION (2026-05-11)
   Accessibility fallback for M4B bracket pulse + M4D hover transition. Per @ui-ninja
   Stage 4 recommendation, brackets stay visible (static warm color, no pulse) and M4D
   appears instantly on hover (no transition). Browser-native prefers-reduced-motion gate.
   +2 !important justified as accessibility exception (per CLAUDE.md exception clause for
   reduced-motion `animation: none !important`). To revert: search CLEAN-FIX-P5-SESSION7-
   P1CTA-M4B-M4D-REDUCED-MOTION and delete between START and END. */
@media (prefers-reduced-motion: reduce) {
    .project-column[data-index="1"] .project-info-column .case-study-cta .view-case-btn::before,
    .project-column[data-index="1"] .project-info-column .case-study-cta .view-case-btn::after {
        animation: none !important;
    }
    .project-column[data-index="1"] .project-info-column .case-study-cta .view-case-btn {
        transition: none !important;
    }
}
/* END CLEAN-FIX-P5-SESSION7-P1CTA-M4B-M4D-REDUCED-MOTION */

