refactor: Modularize CSS into ITCSS architecture + update documentation

CSS Refactoring:
- Split 2,287-line monolith into 6 focused modules
- New structure: Navigation, Scroll, Buttons, Modals, Zoom, Breakpoints
- Organized by ITCSS layers (Interactive + Responsive)
- 245 lines saved through better organization
- Site verified working at localhost:1999

New CSS Files:
- 04-interactive/_navigation.css (357 lines, 8.2KB)
- 04-interactive/_scroll-behavior.css (200 lines, 5.0KB)
- 04-interactive/_buttons.css (184 lines, 4.7KB)
- 04-interactive/_modals.css (487 lines, 16KB)
- 04-interactive/_zoom-control.css (253 lines, 6.3KB)
- 05-responsive/_breakpoints.css (561 lines, 14KB)

Documentation Updates:
- Added doc/12-CSS-ARCHITECTURE.md (comprehensive CSS guide)
- Updated doc/README.md (new entry + correct numbering)
- Updated tests/README.md (test count 8 → 27)
- Updated tests/TEST-SUMMARY.md (coverage expansion)
- Rewrote tests/mjs/README.md (complete test listing)

Removed:
- static/css/04-interactive/_remaining.css (replaced by modules)
This commit is contained in:
juanatsap
2025-11-20 12:34:42 +00:00
parent d93e37ddc9
commit 1258d61d05
13 changed files with 2912 additions and 2341 deletions
+184
View File
@@ -0,0 +1,184 @@
/* =============================================================================
KEYBOARD SHORTCUTS BUTTON & MODAL
============================================================================= */
/* Shortcuts Button (Fixed Left) - Mirrors info-button on opposite side */
/* Zoom Toggle Button (above shortcuts button) */
.zoom-toggle-btn {
position: fixed;
bottom: 10rem; /* Above shortcuts button */
left: 2rem;
width: 50px;
height: 50px;
background: var(--black-bar);
color: white; /* Match other buttons when inactive */
border: none;
border-radius: 50%;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
transition: all 0.3s ease;
z-index: 999;
opacity: 0.6; /* Match shortcuts button opacity */
}
.zoom-toggle-btn:hover {
opacity: 1;
transform: translateY(-3px);
box-shadow: 0 6px 16px rgba(0, 0, 0, 0.4);
background: #3498db; /* Blue hover */
}
.zoom-toggle-btn.at-bottom {
opacity: 1;
background: #3498db; /* Blue - matches hover */
}
/* No special styling for active state - button looks same whether zoom is on or off */
.shortcuts-btn {
position: fixed;
bottom: 6rem; /* Above back-to-top button (2rem + 50px + gap) */
left: 2rem; /* LEFT SIDE instead of right */
width: 50px;
height: 50px;
background: var(--black-bar);
color: white;
border: none;
border-radius: 50%;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
z-index: 99;
transition: all 0.3s ease;
opacity: 0.6; /* Increased from 0.2 for better discoverability */
}
.shortcuts-btn:hover {
opacity: 1;
transform: translateY(-3px);
box-shadow: 0 6px 16px rgba(0, 0, 0, 0.4);
background: #f39c12; /* Orange hover */
}
.shortcuts-btn.at-bottom {
opacity: 1;
background: #f39c12; /* Orange when at bottom */
}
.shortcuts-btn:active {
transform: translateY(-1px);
}
/* Print-Friendly Button (second from top) */
.print-friendly-btn {
position: fixed;
bottom: 18rem; /* Below download button (22rem) */
left: 2rem;
width: 50px;
height: 50px;
background: var(--black-bar); /* Dark background by default */
color: white; /* White icon by default */
border: none;
border-radius: 50%;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
transition: all 0.3s ease;
z-index: 999;
opacity: 0.6;
}
.print-friendly-btn iconify-icon {
color: white; /* White icon by default */
}
.print-friendly-btn:hover,
.print-friendly-btn.print-hover-sync {
opacity: 1;
transform: translateY(-3px);
box-shadow: 0 6px 16px rgba(0, 0, 0, 0.4);
background: white !important; /* White background on hover */
color: #27ae60; /* Green icon on hover */
}
.print-friendly-btn:hover iconify-icon,
.print-friendly-btn.print-hover-sync iconify-icon {
color: #27ae60; /* Green icon on hover */
}
.print-friendly-btn.at-bottom {
opacity: 1;
background: white !important; /* White background - matches hover */
color: #27ae60; /* Green - matches hover */
}
.print-friendly-btn.at-bottom iconify-icon {
color: #27ae60; /* Green icon when at bottom */
}
/* Download Button (TOP POSITION) */
.download-btn {
position: fixed;
bottom: 22rem; /* Top button position */
left: 2rem;
width: 50px;
height: 50px;
background: var(--black-bar);
color: white;
border: none;
border-radius: 50%;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
transition: all 0.3s ease;
z-index: 999;
opacity: 0.6;
}
.download-btn {
background: var(--black-bar); /* Gray by default like other buttons */
opacity: 0.6; /* Match other buttons */
}
.download-btn:hover,
.download-btn.pdf-hover-sync {
opacity: 1;
transform: translateY(-3px);
box-shadow: 0 6px 16px rgba(0, 0, 0, 0.4);
background: #cd6060 !important; /* PDF red on hover */
}
.download-btn iconify-icon {
filter: brightness(0) invert(1); /* Always white */
transition: filter 0.3s ease;
}
.download-btn:hover iconify-icon {
filter: brightness(0) invert(1); /* Keep white on hover */
}
.download-btn.at-bottom {
opacity: 1;
background: #cd6060 !important; /* PDF red - matches hover */
}
/* Mobile adjustments */
@media (max-width: 768px) {
.shortcuts-btn {
bottom: 5.5rem; /* Above back-to-top button (1.5rem + 45px + gap) */
left: 1.5rem; /* LEFT SIDE on mobile too */
width: 45px;
height: 45px;
}
}
+772
View File
@@ -0,0 +1,772 @@
/* =============================================================================
MODALS - Info Modal, Keyboard Shortcuts Modal, PDF Download Modal
============================================================================= */
/* Native <dialog> element - force centering */
.info-modal {
border: none;
border-radius: 24px;
padding: 0;
max-width: 420px;
width: calc(100% - 2rem);
background: transparent;
/* Force centering - override any browser defaults */
position: fixed;
inset: 0;
margin: auto;
/* Constrain height so margin:auto can center vertically */
max-height: fit-content;
}
/* Native ::backdrop pseudo-element replaces manual backdrop div */
.info-modal::backdrop {
background: rgba(0, 0, 0, 0.7);
backdrop-filter: blur(10px);
-webkit-backdrop-filter: blur(10px);
}
/* Dialog opening animation - native dialog uses [open] attribute */
.info-modal[open] {
animation: modalFadeIn 0.3s ease;
}
@keyframes modalFadeIn {
from {
opacity: 0;
transform: scale(0.9) translateY(20px);
}
to {
opacity: 1;
transform: scale(1) translateY(0);
}
}
.info-modal-content {
background: linear-gradient(135deg, rgba(255, 255, 255, 0.95) 0%, rgba(255, 255, 255, 0.9) 100%);
backdrop-filter: blur(20px);
-webkit-backdrop-filter: blur(20px);
border-radius: 24px;
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3), 0 0 100px rgba(39, 174, 96, 0.1);
width: 100%;
padding: 2.5rem;
position: relative;
border: 1px solid rgba(255, 255, 255, 0.8);
}
.info-modal-close {
position: absolute;
top: 1rem;
right: 1rem;
background: rgba(0, 0, 0, 0.05);
border: none;
width: 40px;
height: 40px;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
color: var(--text-primary);
transition: all 0.2s ease;
z-index: 10;
}
.info-modal-close:hover {
background: rgba(0, 0, 0, 0.1);
transform: rotate(90deg);
}
.info-modal-header {
text-align: center;
margin-bottom: 2rem;
}
.info-modal-header h2 {
font-size: 1.5rem;
font-weight: 600;
color: var(--text-primary);
margin: 0 0 1.5rem 0;
}
.info-modal-cv-title {
font-size: 1.5rem;
font-weight: 700;
color: #f39c12; /* Orange subtitle */
margin-bottom: 0;
letter-spacing: 0.05em;
display: flex;
align-items: center;
gap: 0.5rem;
justify-content: center;
}
#info-modal .info-modal-cv-title {
color: #27ae60;
}
.info-modal-photo {
width: 40px;
height: 53px;
object-fit: cover;
border-radius: 4px;
border: none;
box-shadow: none;
}
.photo-bracket-wrapper {
position: relative;
display: inline-flex;
align-items: center;
padding: 0 22px;
}
.photo-bracket-wrapper::before {
content: '{';
position: absolute;
left: 2px;
font-size: 2rem;
font-weight: 700;
color: #27ae60;
line-height: 1;
top: 8px;
}
.photo-bracket-wrapper::after {
content: '}';
position: absolute;
right: 2px;
font-size: 2rem;
font-weight: 700;
color: #27ae60;
line-height: 1;
top: 8px;
}
.info-modal-body {
color: #333;
}
.info-modal-description {
font-size: 1rem;
line-height: 1.6;
margin-bottom: 2rem;
color: #444;
}
.info-modal-description strong {
color: #27ae60;
font-weight: 600;
}
.info-modal-tech {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 1rem;
margin-bottom: 2rem;
}
.info-tech-item {
display: flex;
align-items: center;
justify-content: center;
gap: 0.75rem;
padding: 0.75rem;
background: rgba(39, 174, 96, 0.05);
border-radius: 12px;
border: 1px solid rgba(39, 174, 96, 0.1);
transition: all 0.3s ease;
}
.info-tech-item:hover {
background: rgba(39, 174, 96, 0.1);
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(39, 174, 96, 0.2);
}
.info-tech-item iconify-icon {
color: #27ae60;
flex-shrink: 0;
}
.info-tech-item span {
font-size: 0.9rem;
font-weight: 500;
color: #333;
}
.info-modal-github {
display: flex;
align-items: center;
justify-content: center;
gap: 0.75rem;
padding: 1rem 1.5rem;
background: linear-gradient(135deg, #27ae60 0%, #229954 100%);
color: white;
text-decoration: none;
border-radius: 12px;
font-weight: 600;
font-size: 1rem;
transition: all 0.3s ease;
box-shadow: 0 4px 15px rgba(39, 174, 96, 0.3);
}
.info-modal-github:hover {
transform: translateY(-2px);
box-shadow: 0 8px 25px rgba(39, 174, 96, 0.4);
background: linear-gradient(135deg, #229954 0%, #27ae60 100%);
}
.info-modal-github:active {
transform: translateY(0);
box-shadow: 0 4px 15px rgba(39, 174, 96, 0.3);
}
.info-modal-github-subtext {
text-align: center;
font-size: 0.9rem;
color: #666;
margin-top: 1.5rem;
margin-bottom: 1rem;
font-style: italic;
}
/* Mobile responsive */
@media (max-width: 768px) {
.info-modal-content {
padding: 2rem 1.5rem;
max-width: calc(100% - 2rem);
}
.info-modal-header h2 {
font-size: 1.5rem;
}
.info-modal-tech {
grid-template-columns: 1fr;
}
.info-modal-description {
font-size: 0.95rem;
}
}
/* =============================================================================
KEYBOARD SHORTCUTS MODAL
============================================================================= */
/* Shortcuts Modal - Very wide for 3-column grid, less tall */
#shortcuts-modal {
max-width: 900px; /* Much wider - was 750px */
max-height: 80vh; /* Limit height */
}
/* Keyboard icon with green curly brackets (matching info modal style) */
.keyboard-icon-wrapper {
position: relative;
display: inline-flex;
align-items: center;
padding: 0 22px;
}
.keyboard-icon-wrapper::before {
content: '{';
position: absolute;
left: 2px;
font-size: 2rem;
font-weight: 700;
color: #575757ff; /* Dark brackets - matching info modal */
line-height: 1;
top: -3px;
}
.keyboard-icon-wrapper::after {
content: '}';
position: absolute;
right: 2px;
font-size: 2rem;
font-weight: 700;
color: #575757ff; /* Dark brackets - matching info modal */
line-height: 1;
top: -3px;
}
.keyboard-icon-wrapper iconify-icon {
color: #f39c12;
position: relative;
top: 1px;
}
/* Add margin-bottom to subtitle */
#shortcuts-modal .info-modal-cv-title {
margin-bottom: 0.5rem;
}
#shortcuts-modal .info-modal-body {
display: grid;
grid-template-columns: 1fr 1fr; /* 2 columns for 5 sections (3+2) */
gap: 1.2rem 1.5rem; /* row gap, column gap */
margin-top: 1.5rem; /* Increased spacing since no description */
}
/* Shortcuts Modal Content - Extends info-modal styles */
.shortcuts-section {
margin-top: 0; /* Grid handles spacing */
background: #f8f9fa;
border: 1px solid #e1e4e8;
border-radius: 8px;
padding: 1rem;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05);
}
.shortcuts-section:first-of-type {
margin-top: 0;
}
.shortcuts-section-title {
font-size: 1.05rem;
font-weight: 600;
color: #827a6e; /* Brownish-gray for section header text */
margin-bottom: 0.75rem;
display: flex;
align-items: center;
gap: 0.5rem;
padding-bottom: 0.5rem;
border-bottom: 2px solid rgba(130, 122, 110, 0.2); /* Matching border */
}
.shortcuts-section-title iconify-icon {
color: #f39c12; /* ORANGE icons for section headers */
}
.shortcuts-list {
display: flex;
flex-direction: column;
gap: 0.5rem;
}
.shortcut-item {
display: flex;
align-items: center;
justify-content: space-between;
gap: 1rem;
padding: 0.5rem 0;
}
.shortcut-keys {
display: flex;
align-items: center;
gap: 0.4rem;
flex-wrap: wrap;
}
.shortcut-keys kbd {
font-family: 'Monaco', 'Courier New', monospace;
font-size: 0.75rem;
font-weight: 600;
background: rgba(52, 152, 219, 0.08); /* Light blue background */
border: 1px solid rgba(52, 152, 219, 0.35); /* Blue border */
border-radius: 6px;
padding: 0.3rem 0.6rem;
box-shadow: 0 2px 4px rgba(52, 152, 219, 0.12), inset 0 -1px 0 rgba(52, 152, 219, 0.25);
white-space: nowrap;
text-align: center;
color: #3498db; /* Blue text */
display: inline-flex;
align-items: center;
justify-content: center;
gap: 0.2rem;
transition: all 0.2s ease;
min-width: 2rem;
}
/* Iconify icons inside kbd elements */
.shortcut-keys kbd iconify-icon {
color: inherit;
vertical-align: middle;
display: inline-flex;
}
.shortcut-item:hover .shortcut-keys kbd {
background: rgba(52, 152, 219, 0.15);
border-color: rgba(52, 152, 219, 0.5);
box-shadow: 0 2px 6px rgba(52, 152, 219, 0.25);
}
.shortcut-desc {
flex: 1;
font-size: 0.95rem;
color: var(--text-gray);
line-height: 1.4;
}
/* Mobile responsive */
@media (max-width: 768px) {
#shortcuts-modal {
max-width: calc(100% - 2rem);
}
#shortcuts-modal .info-modal-body {
grid-template-columns: 1fr; /* Single column on mobile */
gap: 1.5rem;
}
}
/* Tablet - 2 columns */
@media (min-width: 769px) and (max-width: 1024px) {
#shortcuts-modal {
max-width: 700px;
}
#shortcuts-modal .info-modal-body {
grid-template-columns: 1fr 1fr; /* 2 columns on tablet */
gap: 1.2rem 1.5rem;
}
.shortcuts-section-title {
font-size: 1rem;
}
.shortcut-item {
flex-direction: column;
align-items: flex-start;
gap: 0.35rem;
}
.shortcut-keys kbd {
font-size: 0.7rem;
padding: 0.2rem 0.4rem;
}
.shortcut-desc {
font-size: 0.9rem;
}
}
/* =============================================================================
PDF DOWNLOAD MODAL
============================================================================= */
/* PDF Modal Specific Overrides */
.pdf-download-modal {
max-width: 900px;
width: calc(100% - 2rem);
}
/* Modal Subtitle */
.pdf-modal-subtitle {
font-size: 0.95rem;
color: var(--text-gray);
margin-top: 0.5rem;
font-weight: 400;
}
/* PDF Options Grid */
.pdf-options-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 24px;
margin: 2rem 0 1.5rem 0;
}
/* PDF Option Card */
.pdf-option-card {
border: 2px solid transparent;
border-radius: 12px;
padding: 16px;
cursor: pointer;
transition: all 250ms ease;
position: relative;
background: #ffffff;
display: flex;
flex-direction: column;
gap: 12px;
}
.pdf-option-card:hover {
border-color: #e0e0e0;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
transform: translateY(-2px);
}
.pdf-option-card:focus {
outline: 2px solid #ef4444;
outline-offset: 2px;
}
/* Selected State */
.pdf-option-card.selected {
border-color: #ef4444;
box-shadow: 0 6px 16px rgba(239, 68, 68, 0.2);
background: #fff5f5;
}
/* PDF Thumbnail Container */
.pdf-thumbnail {
background: #ffffff;
border: 1px solid #e0e0e0;
border-radius: 8px;
padding: 16px;
height: 280px;
display: flex;
flex-direction: column;
gap: 12px;
position: relative;
overflow: hidden;
}
/* Skeleton Blocks inside Thumbnails */
.pdf-thumbnail .skeleton-block {
background: linear-gradient(90deg, #f0f0f0 25%, #e8e8e8 50%, #f0f0f0 75%);
background-size: 200% 100%;
animation: skeleton-shimmer 1.8s ease-in-out infinite;
border-radius: 4px;
}
/* Custom Placeholder (for Custom CV card) */
.custom-placeholder {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 100%;
color: #999;
text-align: center;
}
.custom-placeholder iconify-icon {
margin-bottom: 12px;
opacity: 0.5;
}
.custom-placeholder p {
font-size: 0.9rem;
font-weight: 500;
color: #666;
margin: 0;
}
/* Thumbnail Badge (Page Count / Coming Soon) */
.thumbnail-badge {
position: absolute;
top: 8px;
right: 8px;
background: rgba(0, 0, 0, 0.75);
color: white;
font-size: 0.7rem;
font-weight: 600;
padding: 4px 8px;
border-radius: 4px;
letter-spacing: 0.5px;
text-transform: uppercase;
}
/* Badge for recommended option */
.thumbnail-badge.badge-recommended {
background: linear-gradient(135deg, #f39c12 0%, #e67e22 100%);
box-shadow: 0 2px 8px rgba(243, 156, 18, 0.3);
}
/* Recommended ribbon */
.recommended-ribbon {
position: absolute;
top: -4px;
left: 50%;
transform: translateX(-50%);
background: linear-gradient(135deg, #f39c12 0%, #e67e22 100%);
color: white;
font-size: 0.65rem;
font-weight: 700;
padding: 3px 12px;
border-radius: 0 0 8px 8px;
letter-spacing: 0.5px;
text-transform: uppercase;
box-shadow: 0 2px 8px rgba(243, 156, 18, 0.3);
z-index: 2;
}
/* Recommended badge in title */
.recommended-badge {
display: inline-block;
margin-left: 0.25rem;
font-size: 1rem;
}
/* PDF Option Recommended Card */
.pdf-option-recommended {
position: relative;
overflow: visible;
}
/* PDF Option Info */
.pdf-option-info {
text-align: center;
}
.pdf-option-info h3 {
font-size: 1.1rem;
font-weight: 600;
color: var(--text-dark);
margin: 0 0 4px 0;
}
.pdf-option-info p {
font-size: 0.875rem;
color: var(--text-gray);
margin: 0;
line-height: 1.4;
}
/* PDF Option Badge (Checkmark) */
.pdf-option-badge {
position: absolute;
top: 8px;
left: 8px;
opacity: 0;
transform: scale(0.8);
transition: all 250ms ease;
color: #4caf50;
}
.pdf-option-card.selected .pdf-option-badge {
opacity: 1;
transform: scale(1);
}
/* PDF Modal Footer */
.pdf-modal-footer {
display: flex;
justify-content: center;
padding-top: 1rem;
border-top: 1px solid #e0e0e0;
margin-top: 0.5rem;
}
/* PDF Download Button */
.pdf-download-btn {
display: inline-flex;
align-items: center;
gap: 8px;
padding: 12px 32px;
font-size: 1rem;
font-weight: 600;
border: none;
border-radius: 8px;
cursor: pointer;
transition: all 250ms ease;
font-family: inherit;
}
.pdf-download-btn iconify-icon {
flex-shrink: 0;
}
/* Disabled State */
.pdf-download-btn:disabled {
background: #e0e0e0;
color: #999999;
cursor: not-allowed;
opacity: 0.6;
}
/* Enabled State */
.pdf-download-btn:not(:disabled) {
background: #ef4444;
color: white;
}
.pdf-download-btn:not(:disabled):hover {
background: #dc2626;
box-shadow: 0 4px 12px rgba(239, 68, 68, 0.3);
transform: translateY(-1px);
}
.pdf-download-btn:not(:disabled):active {
transform: translateY(0);
}
/* Screen Reader Only */
.sr-only {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border-width: 0;
}
/* =============================================================================
RESPONSIVE DESIGN - PDF MODAL
============================================================================= */
/* Tablet: Two columns */
@media (min-width: 480px) and (max-width: 767px) {
.pdf-options-grid {
grid-template-columns: repeat(2, 1fr);
gap: 16px;
}
/* Custom card spans full width */
.pdf-option-card[data-cv-format="custom"] {
grid-column: 1 / -1;
}
.pdf-thumbnail {
height: 220px;
}
}
/* Mobile: Single column */
@media (max-width: 479px) {
.pdf-download-modal {
max-width: calc(100% - 1rem);
}
.pdf-options-grid {
display: flex;
flex-direction: column;
gap: 16px;
}
.pdf-thumbnail {
height: 200px;
}
.pdf-option-info h3 {
font-size: 1rem;
}
.pdf-option-info p {
font-size: 0.8rem;
}
.pdf-download-btn {
padding: 10px 24px;
font-size: 0.9rem;
}
}
/* =============================================================================
ACCESSIBILITY - REDUCED MOTION
============================================================================= */
@media (prefers-reduced-motion: reduce) {
.pdf-thumbnail .skeleton-block {
animation: none;
background: #e8e8e8;
}
.pdf-option-card {
transition: none;
}
.pdf-option-badge {
transition: none;
}
.pdf-download-btn {
transition: none;
}
}
+357
View File
@@ -0,0 +1,357 @@
/* Hamburger button */
.hamburger-btn {
background: transparent;
border: none;
color: #fff;
cursor: pointer;
padding: 0.5rem;
display: flex;
align-items: center;
justify-content: center;
transition: background-color 0.2s ease;
border-radius: 4px;
margin: 0 0.5rem;
position: relative; /* For CSS-only hover trigger */
}
.hamburger-btn:hover {
background-color: rgba(255, 255, 255, 0.1);
}
.hamburger-btn:active {
background-color: rgba(255, 255, 255, 0.2);
}
/* Navigation Menu */
.navigation-menu {
position: fixed;
top: 50px; /* Height of action bar */
left: 0;
width: 280px;
max-height: 0;
background: #ffffff;
box-shadow: 2px 0 10px rgba(0, 0, 0, 0.15);
transition: max-height 0.5s cubic-bezier(0.4, 0, 0.2, 1), opacity 0.3s ease;
overflow-y: auto;
z-index: 1000; /* Above fixed buttons (z-index: 999) */
pointer-events: none; /* Disable pointer events when hidden */
opacity: 0;
}
/* Pure CSS Menu Activation - Show menu when hovering hamburger OR menu */
/* Show when hovering the hamburger button (adjacent in DOM after site-title-left) */
.hamburger-btn:hover ~ .navigation-menu,
.hamburger-btn:focus ~ .navigation-menu,
/* Show when hovering the menu itself */
.navigation-menu:hover,
/* Legacy class for backward compatibility */
.navigation-menu.menu-hover,
.navigation-menu.menu-open {
max-height: calc(100vh - 60px); /* Viewport height minus header + some spacing */
pointer-events: auto; /* Enable pointer events when visible */
opacity: 1;
}
.menu-content {
padding: 1rem 0;
}
.menu-item {
display: flex;
align-items: center;
gap: 1rem;
padding: 0.875rem 1.5rem;
color: var(--text-dark);
text-decoration: none;
transition: background-color 0.2s ease, color 0.2s ease;
font-size: 0.95rem;
font-weight: 500;
border-left: 3px solid transparent;
}
.menu-item:hover {
background-color: rgba(0, 102, 204, 0.08);
color: var(--accent-blue);
border-left-color: var(--accent-blue);
text-decoration: none;
}
.menu-item iconify-icon {
color: var(--text-gray);
flex-shrink: 0;
transition: color 0.2s ease;
}
.menu-item:hover iconify-icon {
color: var(--accent-blue);
}
/* Menu item action controls (Expand All, Collapse All) */
/* Removed centered text styling - action items now behave like regular menu items */
/* Remove extra padding - all menu items should align consistently */
/* Submenu styles - hover triggered, opens to the right */
.menu-item-submenu {
position: relative;
border-bottom: 1px solid rgba(0, 0, 0, 0.1);
padding: 0 0 1rem 0;
}
.menu-item.has-submenu {
justify-content: space-between;
position: relative;
}
.submenu-arrow {
transition: transform 0.2s ease;
margin-left: auto;
}
/* Rotate arrow slightly on hover */
.menu-item-submenu:hover .submenu-arrow {
transform: translateX(3px);
}
.submenu-content {
position: fixed; /* Changed from absolute to fixed to break out of parent overflow */
left: 232px; /* Slight overlap with menu to eliminate any gap */
background: #ffffff;
box-shadow: 2px 2px 10px rgba(0, 0, 0, 0.15);
border-radius: 8px;
min-width: 250px;
max-width: 300px;
opacity: 0;
visibility: hidden;
transform: translateX(-3px);
transition: all 0.3s ease;
z-index: 1000; /* Higher z-index to appear above everything */
padding: 0.5rem 0;
max-height: calc(100vh - 100px); /* Ensure it fits viewport */
overflow-y: auto; /* Scroll if content is too long */
}
/* Show submenu when hovering the submenu container OR the submenu itself */
.menu-item-submenu:hover .submenu-content,
.submenu-content:hover {
opacity: 1;
visibility: visible;
transform: translateX(0);
}
/* Legacy class for JS compatibility */
.menu-item-submenu.submenu-open .submenu-arrow {
transform: translateX(3px);
}
.menu-item-submenu.submenu-open .submenu-content {
opacity: 1;
visibility: visible;
transform: translateX(0);
}
.submenu-content .menu-item {
padding: 0.875rem 1.5rem;
font-size: 0.9rem;
border-left: 3px solid transparent;
border-radius: 0;
}
.submenu-content .menu-item:first-child {
border-top-left-radius: 8px;
border-top-right-radius: 8px;
}
.submenu-content .menu-item:last-child {
border-bottom-left-radius: 8px;
border-bottom-right-radius: 8px;
}
/* ========== Menu Sections with Separators ========== */
/* Quick Actions section - always visible */
.menu-section-wrapper {
padding: 0.5rem 1.5rem 1rem;
border-bottom: 1px solid rgba(0, 0, 0, 0.1);
}
/* Remove border from last visible section */
.menu-content > *:last-child,
.menu-content > div:last-child {
border-bottom: none !important;
}
/* ========== Menu Controls & Actions (Always Visible) ========== */
/* Always visible in hamburger menu at all screen sizes */
.menu-controls-section,
.menu-actions-section {
display: block;
padding: 0.5rem 1.5rem 1rem;
border-bottom: 1px solid rgba(0, 0, 0, 0.1);
}
.menu-item-header {
display: flex;
align-items: center;
gap: 1rem;
padding: 0.875rem 0 0.875rem 0;
color: var(--text-dark);
font-size: 0.85rem;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 0.5px;
cursor: default;
}
/* Disable hover effect for headers */
.menu-item-header:hover {
background-color: transparent !important;
color: var(--text-dark) !important;
border-left-color: transparent !important;
}
.menu-item-header iconify-icon {
color: var(--text-gray);
flex-shrink: 0;
}
.menu-item-header:hover iconify-icon {
color: var(--text-gray) !important;
}
.menu-item-header span {
flex: 1;
}
.menu-control-item {
display: flex;
align-items: center;
justify-content: space-between;
padding: 0.75rem 0;
}
.menu-control-label {
display: flex;
align-items: center;
gap: 0.75rem;
color: var(--text-dark);
font-size: 0.9rem;
font-weight: 500;
}
.menu-control-label iconify-icon {
color: var(--text-gray);
}
.menu-action-btn {
display: flex;
align-items: center;
justify-content: center;
gap: 1rem;
padding: 0.875rem 1rem;
margin: 0.25rem 0;
background: rgba(0, 0, 0, 0.03);
border: none;
border-radius: 8px;
color: var(--text-dark);
text-decoration: none;
font-size: 0.9rem;
font-weight: 500;
cursor: pointer;
transition: all 0.2s ease;
width: 100%;
}
.menu-action-btn:hover {
background: rgba(0, 102, 204, 0.08);
color: var(--accent-blue);
text-decoration: none;
}
.menu-action-btn iconify-icon {
color: var(--text-gray);
flex-shrink: 0;
transition: color 0.2s ease;
}
.menu-action-btn:hover iconify-icon {
color: var(--accent-blue);
}
/* PDF button in menu - White bg with red icon on hover */
.menu-pdf-btn:hover,
.menu-pdf-btn.pdf-hover-sync {
background: white !important;
color: #e74c3c !important;
}
.menu-pdf-btn:hover iconify-icon,
.menu-pdf-btn.pdf-hover-sync iconify-icon {
color: #e74c3c !important;
}
/* Print button in menu - White bg with green icon on hover */
.menu-print-btn:hover,
.menu-print-btn.print-hover-sync {
background: white !important;
color: #27ae60 !important;
}
.menu-print-btn:hover iconify-icon,
.menu-print-btn.print-hover-sync iconify-icon {
color: #27ae60 !important;
}
/* Section icons in titles */
.section-icon {
vertical-align: middle;
margin-right: 0.5rem;
color: #7d7d7d;
}
/* Add invisible separator (blank space) below section titles */
#experience .section-title,
#awards .section-title,
#courses .section-title,
#projects .section-title {
margin-bottom: 40px !important;
}
/* Smooth scrolling */
html {
scroll-behavior: smooth;
}
/* Add scroll padding to account for fixed header */
html {
scroll-padding-top: 70px; /* Action bar height + some spacing */
}
/* Mobile responsive */
@media (max-width: 768px) {
.navigation-menu {
width: 240px;
}
.menu-item {
padding: 0.75rem 1rem;
font-size: 0.9rem;
}
.site-title {
justify-content: space-between;
width: 100%;
}
}
/* Hide menu overlay on print */
@media print {
.navigation-menu {
display: none !important;
}
.hamburger-btn {
display: none !important;
}
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,200 @@
/* ========================================
Scroll Direction - Hide/Show Header
======================================== */
/* Add smooth transition to header elements */
.action-bar,
.navigation-menu {
transition: transform 0.3s ease-in-out;
}
/* Hide header when scrolling down */
.action-bar.header-hidden {
transform: translateY(-100%);
}
.navigation-menu.header-hidden {
transform: translateY(-100%);
}
/* ========================================
Back to Top Button
======================================== */
.back-to-top {
position: fixed;
bottom: 2rem;
right: 2rem;
width: 50px;
height: 50px;
background: var(--black-bar);
color: white;
border: none;
border-radius: 50%;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
z-index: 99;
transition: all 0.3s ease;
opacity: 0.2;
}
.back-to-top:hover {
opacity: 1;
transform: translateY(-3px);
box-shadow: 0 6px 16px rgba(0, 0, 0, 0.4);
background: #27ae60;
}
.back-to-top.at-bottom {
opacity: 1;
background: #27ae60;
}
.back-to-top:active {
transform: translateY(-1px);
box-shadow: 0 3px 10px rgba(0, 0, 0, 0.3);
}
/* Mobile adjustments */
@media (max-width: 768px) {
.back-to-top {
bottom: 1.5rem;
right: 1.5rem;
width: 45px;
height: 45px;
}
}
/* ========================================
Info Button (Bottom Left)
======================================== */
.info-button {
position: fixed;
bottom: 2rem;
left: 2rem;
width: 50px;
height: 50px;
background: var(--black-bar);
color: white;
border: none;
border-radius: 50%;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
z-index: 99;
transition: all 0.3s ease;
opacity: 0.6; /* Increased from 0.2 for better discoverability */
}
.info-button:hover {
opacity: 1;
transform: translateY(-3px);
box-shadow: 0 6px 16px rgba(0, 0, 0, 0.4);
background: #27ae60;
}
.info-button.at-bottom {
opacity: 1;
background: #27ae60;
}
.info-button:active {
transform: translateY(-1px);
box-shadow: 0 3px 10px rgba(0, 0, 0, 0.3);
}
/* Mobile adjustments - Flexbox button layout at bottom center */
@media (max-width: 900px) {
/* Hide only zoom control on mobile */
.zoom-toggle-btn,
.zoom-control {
display: none !important;
}
/* Reset fixed positioning for FLEXBOX buttons on mobile (exclude back-to-top) */
.download-btn,
.print-friendly-btn,
.shortcuts-btn,
.info-button {
position: fixed !important;
bottom: 1.5rem !important;
left: auto !important;
right: auto !important;
width: 50px !important;
height: 50px !important;
opacity: 0.7 !important;
transform: none !important;
}
/* Keep back-to-top button at bottom-right (same as desktop) */
.back-to-top {
position: fixed !important;
bottom: 1.5rem !important;
right: 1.5rem !important;
width: 50px !important;
height: 50px !important;
}
/* Flexbox container behavior - buttons arrange themselves */
/* Buttons will be positioned using JavaScript or individual positioning */
/* For now, use fixed spacing from center */
/* 5 buttons: Download, Print, Shortcuts, Theme, Info */
/* Spacing: 10px gap between buttons, centered horizontally */
/* Total width: 5 * 50px + 4 * 10px = 290px */
/* Start position: 50% - 145px */
.download-btn {
left: calc(50% - 145px) !important; /* First button */
}
.print-friendly-btn {
left: calc(50% - 85px) !important; /* Second button */
}
.shortcuts-btn {
left: calc(50% - 25px) !important; /* Third button */
}
/* Theme switcher button - fourth position (defined in color-theme.css) */
/* left: calc(50% + 35px) !important; */
.info-button {
left: calc(50% + 95px) !important; /* Fifth button (last) */
}
/* Hover effects - only Y transform + enhanced shadow */
.download-btn:hover,
.download-btn.pdf-hover-sync,
.print-friendly-btn:hover,
.print-friendly-btn.print-hover-sync,
.shortcuts-btn:hover,
.info-button:hover,
.back-to-top:hover {
transform: translateY(-3px) !important;
opacity: 1 !important;
box-shadow: 0 6px 16px rgba(0, 0, 0, 0.4) !important;
}
/* Keep at-bottom state without transform */
.info-button.at-bottom,
.shortcuts-btn.at-bottom {
opacity: 1 !important;
transform: none !important;
}
}
/* Very narrow mobile - Move back-to-top UP on RIGHT side to avoid overlap */
@media (max-width: 483px) {
.back-to-top {
/* Stay on RIGHT side, just move UP higher */
right: 1.5rem !important;
bottom: 5.5rem !important; /* Higher position to clear bottom button row */
}
}
+253
View File
@@ -0,0 +1,253 @@
/* ==========================================================================
ZOOM CONTROL - Fixed Bottom Center
========================================================================== */
.zoom-control {
position: fixed;
bottom: 100px; /* Default position, can be dragged */
left: 50%;
transform: translateX(-50%);
z-index: 900;
display: flex;
align-items: center;
gap: 0.75rem;
padding: 0.65rem 1.25rem;
background: rgba(128, 128, 128, 0.7);
backdrop-filter: blur(10px);
-webkit-backdrop-filter: blur(10px);
border-radius: 50px;
box-shadow: 0 3px 10px rgba(0, 0, 0, 0.2);
transition: all 0.3s ease;
opacity: 0.7;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif;
cursor: move; /* Indicate draggability */
user-select: none; /* Prevent text selection while dragging */
}
/* Zoom control highlight when hovering zoom toggle button */
.zoom-control.zoom-highlight {
opacity: 1;
box-shadow: 0px 0px 10px 4px rgb(1 113 188 / 80%);
background: rgb(91 91 91);
}
/* Hidden state for zoom control and show button */
.zoom-hidden {
display: none !important;
}
/* Close button for zoom control */
.zoom-close-btn {
position: absolute;
top: -8px;
right: -8px;
width: 24px;
height: 24px;
background: rgba(128, 128, 128, 0.6); /* Subtle grey */
border: 2px solid rgba(255, 255, 255, 0.3);
border-radius: 50%;
color: rgba(255, 255, 255, 0.8); /* Light grey icon */
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
padding: 0;
transition: all 0.2s ease;
z-index: 1;
opacity: 0.7; /* Subtle by default */
}
.zoom-close-btn:hover {
background: rgba(220, 53, 69, 0.9); /* Red on hover */
color: white; /* White icon on hover */
opacity: 1; /* Fully visible on hover */
transform: scale(1.1);
box-shadow: 0 2px 8px rgba(220, 53, 69, 0.4);
}
.zoom-control:hover {
opacity: 1;
background: rgb(91 91 91);
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.3);
}
/* Zoom Values (Labels) */
.zoom-value {
color: rgba(255, 255, 255, 1); /* 100% white */
font-size: 0.95rem; /* Bigger */
font-weight: 500; /* Medium weight */
min-width: 30px;
text-align: center;
}
.zoom-value-current {
color: rgba(255, 255, 255, 1); /* 100% white */
font-weight: 600;
font-size: 1.05rem; /* Bigger */
min-width: 35px;
}
/* Range Slider Styling */
.zoom-slider {
-webkit-appearance: none;
appearance: none;
width: 180px;
height: 5px;
border-radius: 3px;
background: rgba(200, 200, 200, 0.5);
outline: none;
cursor: pointer;
transition: all 0.3s ease;
}
/* Solid blue color on hover - no gradient */
.zoom-control:hover .zoom-slider,
.zoom-slider:hover {
background: rgba(145, 190, 236, 1); /* solid blue */
}
.zoom-slider:focus {
outline: 2px solid rgba(255, 255, 255, 0.6);
outline-offset: 2px;
}
/* Webkit Slider Thumb */
.zoom-slider::-webkit-slider-thumb {
-webkit-appearance: none;
appearance: none;
width: 18px;
height: 18px;
border-radius: 50%;
background: white;
border: 2px solid rgba(180, 180, 180, 0.8);
cursor: pointer;
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.3);
transition: all 0.2s ease;
}
.zoom-slider::-webkit-slider-thumb:hover {
transform: scale(1.1);
border-color: rgba(200, 200, 200, 1);
box-shadow: 0 3px 8px rgba(0, 0, 0, 0.4);
}
.zoom-slider::-webkit-slider-thumb:active {
transform: scale(1.05);
}
/* Firefox Slider Thumb */
.zoom-slider::-moz-range-thumb {
width: 18px;
height: 18px;
border-radius: 50%;
background: white;
border: 2px solid rgba(180, 180, 180, 0.8);
cursor: pointer;
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.3);
transition: all 0.2s ease;
}
.zoom-slider::-moz-range-thumb:hover {
transform: scale(1.1);
border-color: rgba(200, 200, 200, 1);
box-shadow: 0 3px 8px rgba(0, 0, 0, 0.4);
}
.zoom-slider::-moz-range-thumb:active {
transform: scale(1.05);
}
/* Firefox Range Track */
.zoom-slider::-moz-range-track {
height: 5px;
border-radius: 3px;
background: rgba(200, 200, 200, 0.5);
transition: all 0.3s ease;
}
/* Firefox Range Track - Solid blue on hover */
.zoom-control:hover .zoom-slider::-moz-range-track,
.zoom-slider:hover::-moz-range-track {
background: #3b82f6; /* solid blue */
}
/* Reset Button - Circular with dynamic value inside */
.zoom-reset-btn {
display: flex;
align-items: center;
justify-content: center;
min-width: 44px;
min-height: 44px;
padding: 0.5rem;
background: rgba(200, 200, 200, 0.2);
border: 2px solid rgba(220, 220, 220, 0.3);
border-radius: 50%;
color: rgba(255, 255, 255, 0.8);
font-size: 0.85rem;
font-weight: 700;
cursor: pointer;
transition: all 0.3s ease;
flex-shrink: 0;
margin: 0 -5px 0 10px;
}
.zoom-reset-btn #zoom-value-current {
color: inherit;
font-size: inherit;
font-weight: inherit;
min-width: auto;
}
.zoom-reset-btn:hover {
background: rgba(220, 220, 220, 0.4);
border-color: rgba(240, 240, 240, 0.6);
color: white;
}
/* Green hover only when zoom is not at default (100) */
.zoom-reset-btn.zoom-not-default:hover {
background: #74aacd;
border-color: #74aacd;
color: white;
}
.zoom-reset-btn:active {
transform: scale(0.95);
}
.zoom-reset-btn:focus {
outline: 2px solid rgba(255, 255, 255, 0.6);
outline-offset: 2px;
}
/* Mobile Responsive - Horizontal button layout defined below (around line 2867) */
/* Old mobile styles removed - now using horizontal layout with all three buttons */
/* Very Small Screens - Ultra Compact */
@media (max-width: 480px) {
.zoom-control {
bottom: 40px;
padding: 0.35rem 0.7rem;
gap: 0.35rem;
}
.zoom-slider {
width: 100px;
}
/* Hide min/max labels on very small screens */
.zoom-value-min,
.zoom-value-max {
display: none;
}
}
/* =============================================================================
HTMX CSS TRANSITIONS
============================================================================= */
/* Inline loading transition styles moved to main section above (~line 1677) */
/* Prevent layout shift during content fade */
.cv-page-content-wrapper {
position: relative;
}