my personal site
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Refactor index.html: Update meta tags for improved SEO and accessibility, enhance theme handling with new color-scheme attributes, and remove outdated privacy and project pages. Consolidate styles and scripts for better performance and maintainability.

+323 -3674
.DS_Store

This is a binary file and will not be displayed.

Jack_Hannon_Marketing_Resume_Web.pdf

This is a binary file and will not be displayed.

Jack_Hannon__Resume_Web.pdf

This is a binary file and will not be displayed.

images/Troop-180A.png

This is a binary file and will not be displayed.

images/VT-Gym-Tracker-ios-Icon.png

This is a binary file and will not be displayed.

images/Yik Yak VT/YYVT-1.png

This is a binary file and will not be displayed.

images/Yik Yak VT/YYVT-2.png

This is a binary file and will not be displayed.

images/Yik Yak VT/YYVT-3.png

This is a binary file and will not be displayed.

-1
images/bluesky-brands-solid.svg
··· 1 - <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--!Font Awesome Free 6.7.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2025 Fonticons, Inc.--><path d="M111.8 62.2C170.2 105.9 233 194.7 256 242.4c23-47.6 85.8-136.4 144.2-180.2c42.1-31.6 110.3-56 110.3 21.8c0 15.5-8.9 130.5-14.1 149.2C478.2 298 412 314.6 353.1 304.5c102.9 17.5 129.1 75.5 72.5 133.5c-107.4 110.2-154.3-27.6-166.3-62.9l0 0c-1.7-4.9-2.6-7.8-3.3-7.8s-1.6 3-3.3 7.8l0 0c-12 35.3-59 173.1-166.3 62.9c-56.5-58-30.4-116 72.5-133.5C100 314.6 33.8 298 15.7 233.1C10.4 214.4 1.5 99.4 1.5 83.9c0-77.8 68.2-53.4 110.3-21.8z"/></svg>
-1
images/github-brands.svg
··· 1 - <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 496 512"><!--!Font Awesome Free 6.7.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2025 Fonticons, Inc.--><path d="M165.9 397.4c0 2-2.3 3.6-5.2 3.6-3.3 .3-5.6-1.3-5.6-3.6 0-2 2.3-3.6 5.2-3.6 3-.3 5.6 1.3 5.6 3.6zm-31.1-4.5c-.7 2 1.3 4.3 4.3 4.9 2.6 1 5.6 0 6.2-2s-1.3-4.3-4.3-5.2c-2.6-.7-5.5 .3-6.2 2.3zm44.2-1.7c-2.9 .7-4.9 2.6-4.6 4.9 .3 2 2.9 3.3 5.9 2.6 2.9-.7 4.9-2.6 4.6-4.6-.3-1.9-3-3.2-5.9-2.9zM244.8 8C106.1 8 0 113.3 0 252c0 110.9 69.8 205.8 169.5 239.2 12.8 2.3 17.3-5.6 17.3-12.1 0-6.2-.3-40.4-.3-61.4 0 0-70 15-84.7-29.8 0 0-11.4-29.1-27.8-36.6 0 0-22.9-15.7 1.6-15.4 0 0 24.9 2 38.6 25.8 21.9 38.6 58.6 27.5 72.9 20.9 2.3-16 8.8-27.1 16-33.7-55.9-6.2-112.3-14.3-112.3-110.5 0-27.5 7.6-41.3 23.6-58.9-2.6-6.5-11.1-33.3 2.6-67.9 20.9-6.5 69 27 69 27 20-5.6 41.5-8.5 62.8-8.5s42.8 2.9 62.8 8.5c0 0 48.1-33.6 69-27 13.7 34.7 5.2 61.4 2.6 67.9 16 17.7 25.8 31.5 25.8 58.9 0 96.5-58.9 104.2-114.8 110.5 9.2 7.9 17 22.9 17 46.4 0 33.7-.3 75.4-.3 83.6 0 6.5 4.6 14.4 17.3 12.1C428.2 457.8 496 362.9 496 252 496 113.3 383.5 8 244.8 8zM97.2 352.9c-1.3 1-1 3.3 .7 5.2 1.6 1.6 3.9 2.3 5.2 1 1.3-1 1-3.3-.7-5.2-1.6-1.6-3.9-2.3-5.2-1zm-10.8-8.1c-.7 1.3 .3 2.9 2.3 3.9 1.6 1 3.6 .7 4.3-.7 .7-1.3-.3-2.9-2.3-3.9-2-.6-3.6-.3-4.3 .7zm32.4 35.6c-1.6 1.3-1 4.3 1.3 6.2 2.3 2.3 5.2 2.6 6.5 1 1.3-1.3 .7-4.3-1.3-6.2-2.2-2.3-5.2-2.6-6.5-1zm-11.4-14.7c-1.6 1-1.6 3.6 0 5.9 1.6 2.3 4.3 3.3 5.6 2.3 1.6-1.3 1.6-3.9 0-6.2-1.4-2.3-4-3.3-5.6-2z"/></svg>
-1
images/linkedin-brands.svg
··· 1 - <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--!Font Awesome Free 6.7.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2025 Fonticons, Inc.--><path d="M416 32H31.9C14.3 32 0 46.5 0 64.3v383.4C0 465.5 14.3 480 31.9 480H416c17.6 0 32-14.5 32-32.3V64.3c0-17.8-14.4-32.3-32-32.3zM135.4 416H69V202.2h66.5V416zm-33.2-243c-21.3 0-38.5-17.3-38.5-38.5S80.9 96 102.2 96c21.2 0 38.5 17.3 38.5 38.5 0 21.3-17.2 38.5-38.5 38.5zm282.1 243h-66.4V312c0-24.8-.5-56.7-34.5-56.7-34.6 0-39.9 27-39.9 54.9V416h-66.4V202.2h63.7v29.2h.9c8.9-16.8 30.6-34.5 62.9-34.5 67.2 0 79.7 44.3 79.7 101.9V416z"/></svg>
images/orbyt-icon.png

This is a binary file and will not be displayed.

images/vt-gym-Data.png

This is a binary file and will not be displayed.

images/vt-gym-hours.png

This is a binary file and will not be displayed.

images/vt-gym-screenshot.jpeg

This is a binary file and will not be displayed.

images/vt-gym-widgets.png

This is a binary file and will not be displayed.

images/yikyak-profile.jpg

This is a binary file and will not be displayed.

+135 -139
index.html
··· 1 1 <!DOCTYPE html> 2 2 <html lang="en"> 3 3 <head> 4 - <meta charset="UTF-8" /> 5 - <meta name="viewport" content="width=device-width, initial-scale=1.0" /> 6 - <title>Jack Hannon | About</title> 7 - <script> 8 - // Apply saved theme or OS preference before CSS loads to prevent flash 9 - if (localStorage.getItem('theme') === 'dark' || 10 - (!localStorage.getItem('theme') && window.matchMedia('(prefers-color-scheme: dark)').matches)) { 11 - document.documentElement.classList.add('dark-theme'); 4 + <meta charset="utf-8"> 5 + <meta name="viewport" content="width=device-width, initial-scale=1"> 6 + <meta name="color-scheme" content="light dark"> 7 + <meta name="theme-color" content="#f8fafc" media="(prefers-color-scheme: light)"> 8 + <meta name="theme-color" content="#0f172a" media="(prefers-color-scheme: dark)"> 9 + <link rel="preconnect" href="https://fonts.googleapis.com"> 10 + <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> 11 + <link href="https://fonts.googleapis.com/css2?family=Schibsted+Grotesk:ital,wght@0,400..900;1,400..900&display=swap" rel="stylesheet"> 12 + <link rel="stylesheet" href="style.css"> 13 + <link rel="icon" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'><text y='.9em' font-size='90'>🎯</text></svg>"> 14 + <title>Jack Hannon</title> 15 + <meta name="description" content="Marketing specialist and Virginia Tech graduate"> 16 + <meta name="author" content="Jack Hannon"> 17 + <link rel="canonical" href="https://jackhannon.me/"> 18 + <meta property="og:type" content="profile"> 19 + <meta property="og:site_name" content="Jack Hannon"> 20 + <meta property="og:locale" content="en_US"> 21 + <meta property="og:title" content="Jack Hannon"> 22 + <meta property="og:description" content="Marketing specialist and Virginia Tech graduate"> 23 + <meta property="og:url" content="https://jackhannon.me/"> 24 + <meta property="profile:first_name" content="Jack"> 25 + <meta property="profile:last_name" content="Hannon"> 26 + <meta property="profile:username" content="jackphannon"> 27 + <meta name="twitter:card" content="summary"> 28 + <meta name="twitter:title" content="Jack Hannon"> 29 + <meta name="twitter:description" content="Marketing specialist and Virginia Tech graduate"> 30 + <script type="application/ld+json"> 31 + { 32 + "@context": "https://schema.org", 33 + "@type": "Person", 34 + "@id": "https://jackhannon.me/#person", 35 + "name": "Jack Hannon", 36 + "givenName": "Jack", 37 + "familyName": "Hannon", 38 + "alternateName": "jackphannon", 39 + "sameAs": [ 40 + "https://www.linkedin.com/in/jackphannon/", 41 + "https://github.com/Hann8n", 42 + "https://bsky.app/profile/jack.orbyt.video" 43 + ], 44 + "url": "https://jackhannon.me", 45 + "alumniOf": { 46 + "@type": "CollegeOrUniversity", 47 + "name": "Virginia Tech" 12 48 } 49 + } 13 50 </script> 14 - <link rel="stylesheet" href="style.css" /> 15 - <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@20..48,100..700,0..1,-50..200&icon_names=match_case" /> 16 - <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css" /> 17 - <style> 18 - .material-symbols-outlined { 19 - font-variation-settings: 20 - 'FILL' 0, 21 - 'wght' 400, 22 - 'GRAD' 0, 23 - 'opsz' 24 24 - } 25 - </style> 26 51 </head> 27 52 <body> 28 - <a href="#main-content" class="skip-link">Skip to main content</a> 29 - <header> 30 - <nav class="container" role="navigation" aria-label="Main navigation" style="display: flex; align-items: center; justify-content: space-between;"> 31 - <a href="index.html" class="brand" id="brand">Jack Hannon</a> 32 - <div class="header-controls" id="header-controls" style="margin-left: auto; display: flex; align-items: center;"> 33 - <button class="mobile-nav-toggle" aria-controls="header-controls" aria-expanded="false" aria-label="Open navigation menu"> 34 - <span class="hamburger-icon"></span> 35 - </button> 36 - <ul class="menu" role="menubar" id="main-menu"> 37 - <li><a href="index.html" class="active" role="menuitem" tabindex="0">About</a></li> 38 - <li><a href="projects.html" role="menuitem" tabindex="0">Projects</a></li> 39 - <li><a href="resume.html" role="menuitem" tabindex="0">Resume</a></li> 40 - </ul> 41 - <div class="header-divider"></div> 42 - <span id="accessibility-btn" class="accessibility-icon" aria-label="Accessibility options" aria-haspopup="true" aria-expanded="false" tabindex="0"> 43 - <span class="material-symbols-outlined" aria-hidden="true">match_case</span> 44 - </span> 45 - <div id="accessibility-menu" class="accessibility-menu" style="display:none;" role="menu" aria-label="Accessibility options"> 46 - <div class="access-section"> 47 - <div class="access-label">Theme</div> 48 - <div class="access-theme-btns"> 49 - <label class="access-radio"><input type="radio" name="theme-mode" value="system" /> System</label> 50 - <label class="access-radio"><input type="radio" name="theme-mode" value="light" /> Light</label> 51 - <label class="access-radio"><input type="radio" name="theme-mode" value="dark" /> Dark</label> 52 - </div> 53 - </div> 54 - <div class="access-section"> 55 - <label class="access-toggle"><input type="checkbox" id="high-contrast-toggle" /> High Contrast</label> 56 - </div> 57 - <div class="access-section access-textsize"> 58 - <div class="access-label">Text Size</div> 59 - <div class="access-textsize-btns"> 60 - <button type="button" id="text-decrease" class="textsize-round" aria-label="Decrease text size">–</button> 61 - <span id="text-reset" class="textsize-reset" tabindex="0" role="button" aria-label="Reset text size">Reset</span> 62 - <button type="button" id="text-increase" class="textsize-round" aria-label="Increase text size">+</button> 63 - </div> 64 - </div> 65 - </div> 66 - </div> 67 - </nav> 68 - </header> 69 - <main class="container" id="main-content"> 70 - <div id="a11y-status" class="visually-hidden" aria-live="polite" aria-atomic="true"></div> 71 - <section class="intro profile-header"> 72 - <div class="intro-text profile-header-content"> 73 - <img src="headshot.jpg" alt="Jack Hannon headshot" class="headshot profile-avatar" /> 74 - <div class="name-and-social"> 75 - <h1 class="profile-name">Jack Hannon</h1> 76 - <div class="social-links"> 77 - <a href="https://www.linkedin.com/in/jackphannon/" target="_blank" rel="noopener noreferrer" aria-label="LinkedIn Profile"> 78 - <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512" class="linkedin-icon"> 79 - <path d="M416 32H31.9C14.3 32 0 46.5 0 64.3v383.4C0 465.5 14.3 480 31.9 480H416c17.6 0 32-14.5 32-32.3V64.3c0-17.8-14.4-32.3-32-32.3zM135.4 416H69V202.2h66.5V416zm-33.2-243c-21.3 0-38.5-17.3-38.5-38.5S80.9 96 102.2 96c21.2 0 38.5 17.3 38.5 38.5 0 21.3-17.2 38.5-38.5 38.5zm282.1 243h-66.4V312c0-24.8-.5-56.7-34.5-56.7-34.6 0-39.9 27-39.9 54.9V416h-66.4V202.2h63.7v29.2h.9c8.9-16.8 30.6-34.5 62.9-34.5 67.2 0 79.7 44.3 79.7 101.9V416z"/> 80 - </svg> 81 - </a> 82 - <a href="https://github.com/Hann8n" target="_blank" rel="noopener noreferrer" aria-label="GitHub Profile"> 83 - <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 496 512" class="github-icon"> 84 - <path d="M165.9 397.4c0 2-2.3 3.6-5.2 3.6-3.3 .3-5.6-1.3-5.6-3.6 0-2 2.3-3.6 5.2-3.6 3-.3 5.6 1.3 5.6 3.6zm-31.1-4.5c-.7 2 1.3 4.3 4.3 4.9 2.6 1 5.6 0 6.2-2s-1.3-4.3-4.3-5.2c-2.6-.7-5.5 .3-6.2 2.3zm44.2-1.7c-2.9 .7-4.9 2.6-4.6 4.9 .3 2 2.9 3.3 5.9 2.6 2.9-.7 4.9-2.6 4.6-4.6-.3-1.9-3-3.2-5.9-2.9zM244.8 8C106.1 8 0 113.3 0 252c0 110.9 69.8 205.8 169.5 239.2 12.8 2.3 17.3-5.6 17.3-12.1 0-6.2-.3-40.4-.3-61.4 0 0-70 15-84.7-29.8 0 0-11.4-29.1-27.8-36.6 0 0-22.9-15.7 1.6-15.4 0 0 24.9 2 38.6 25.8 21.9 38.6 58.6 27.5 72.9 20.9 2.3-16 8.8-27.1 16-33.7-55.9-6.2-112.3-14.3-112.3-110.5 0-27.5 7.6-41.3 23.6-58.9-2.6-6.5-11.1-33.3 2.6-67.9 20.9-6.5 69 27 69 27 20-5.6 41.5-8.5 62.8-8.5s42.8 2.9 62.8 8.5c0 0 48.1-33.6 69-27 13.7 34.7 5.2 61.4 2.6 67.9 16 17.7 25.8 31.5 25.8 58.9 0 96.5-58.9 104.2-114.8 110.5 9.2 7.9 17 22.9 17 46.4 0 33.7-.3 75.4-.3 83.6 0 6.5 4.6 14.4 17.3 12.1C428.2 457.8 496 362.9 496 252 496 113.3 383.5 8 244.8 8zM97.2 352.9c-1.3 1-1 3.3 .7 5.2 1.6 1.6 3.9 2.3 5.2 1 1.3-1 1-3.3-.7-5.2-1.6-1.6-3.9-2.3-5.2-1zm-10.8-8.1c-.7 1.3 .3 2.9 2.3 3.9 1.6 1 3.6 .7 4.3-.7 .7-1.3-.3-2.9-2.3-3.9-2-.6-3.6-.3-4.3 .7zm32.4 35.6c-1.6 1.3-1 4.3 1.3 6.2 2.3 2.3 5.2 2.6 6.5 1 1.3-1.3 .7-4.3-1.3-6.2-2.2-2.3-5.2-2.6-6.5-1zm-11.4-14.7c-1.6 1-1.6 3.6 0 5.9 1.6 2.3 4.3 3.3 5.6 2.3 1.6-1.3 1.6-3.9 0-6.2-1.4-2.3-4-3.3-5.6-2z"/> 85 - </svg> 86 - </a> 87 - <a href="https://bsky.app/profile/jackhannon.me" target="_blank" rel="noopener noreferrer" aria-label="Bluesky Profile"> 88 - <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" class="bluesky-icon"> 89 - <path d="M111.8 62.2C170.2 105.9 233 194.7 256 242.4c23-47.6 85.8-136.4 144.2-180.2c42.1-31.6 110.3-56 110.3 21.8c0 15.5-8.9 130.5-14.1 149.2C478.2 298 412 314.6 353.1 304.5c102.9 17.5 129.1 75.5 72.5 133.5c-107.4 110.2-154.3-27.6-166.3-62.9l0 0c-1.7-4.9-2.6-7.8-3.3-7.8s-1.6 3-3.3 7.8l0 0c-12 35.3-59 173.1-166.3 62.9c-56.5-58-30.4-116 72.5-133.5C100 314.6 33.8 298 15.7 233.1C10.4 214.4 1.5 99.4 1.5 83.9c0-77.8 68.2-53.4 110.3-21.8z"/> 90 - </svg> 91 - </a> 92 - </div> 93 - </div> 94 - <p class="tagline profile-tagline"> 95 - Adobe Suite 96 - <span class="sep">|</span> Google Ads 97 - <span class="sep">|</span> HubSpot certified 98 - </p> 99 - <p class="profile-bio"> 100 - I'm a recent Virginia Tech graduate with a B.A. in Advertising and a passion for connecting communities through creative marketing. I specialize in social media outreach, content creation, and event coordination. 101 - </p> 53 + <main> 54 + <div class="content-wrapper"> 55 + <div class="profile-container"> 56 + <section class="profile-section"> 57 + <figure class="profile-figure" itemscope itemtype="https://schema.org/Person"> 58 + <picture class="avatar-wrapper"> 59 + <img 60 + alt="Jack Hannon" 61 + fetchpriority="high" 62 + itemprop="image" 63 + src="headshot.jpg" 64 + width="76" 65 + height="76" 66 + class="avatar" 67 + > 68 + </picture> 69 + <figcaption class="profile-caption"> 70 + <p> 71 + <span itemprop="name" lang="en" translate="no" class="profile-name">Jack Hannon</span> 72 + </p> 73 + <div class="profile-location-wrapper"> 74 + <p itemscope itemprop="alumniOf" itemtype="https://schema.org/CollegeOrUniversity" class="profile-location"> 75 + <svg class="location-icon vt-logo" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 206.1925 98.1875" aria-hidden="true"><g transform="matrix(1.25 0 0 -1.25 -127.51 602.7)"><g transform="translate(.77443 .77443)"><path class="vt-path" d="m108.14 476.89h20.034l14.814-27.544 15.446 27.544h100.79l-9.184-17.112h-27.752l-27.547-51.75h-20.24l27.751 51.54h-32.97l-26.082-48.203-35.06 65.525z"/></g></g></svg> 76 + <span itemprop="name">Class of 2025</span> 77 + </p> 78 + </div> 79 + </figcaption> 80 + </figure> 81 + <ul class="social-links"> 82 + <li> 83 + <a rel="noopener noreferrer external" target="_blank" class="social-link" href="https://www.linkedin.com/in/jackphannon/" title="LinkedIn: jackphannon"> 84 + <figure class="social-icon-wrapper"> 85 + <svg class="social-icon" focusable="false" role="img" viewBox="0 0 448 512" aria-hidden="true"> 86 + <path d="M416 32H31.9C14.3 32 0 46.5 0 64.3v383.4C0 465.5 14.3 480 31.9 480H416c17.6 0 32-14.5 32-32.3V64.3c0-17.8-14.4-32.3-32-32.3zM135.4 416H69V202.2h66.5V416zm-33.2-243c-21.3 0-38.5-17.3-38.5-38.5S80.9 96 102.2 96c21.2 0 38.5 17.3 38.5 38.5 0 21.3-17.2 38.5-38.5 38.5zm282.1 243h-66.4V312c0-24.8-.5-56.7-34.5-56.7-34.6 0-39.9 27-39.9 54.9V416h-66.4V202.2h63.7v29.2h.9c8.9-16.8 30.6-34.5 62.9-34.5 67.2 0 79.7 44.3 79.7 101.9V416z"/> 87 + </svg> 88 + </figure> 89 + <span class="social-label">jackphannon</span> 90 + </a> 91 + </li> 92 + <li> 93 + <a rel="noopener noreferrer external" target="_blank" class="social-link" href="https://github.com/Hann8n" title="GitHub: Hann8n"> 94 + <figure class="social-icon-wrapper"> 95 + <svg class="social-icon" focusable="false" role="img" viewBox="0 0 496 512" aria-hidden="true"> 96 + <path d="M165.9 397.4c0 2-2.3 3.6-5.2 3.6-3.3 .3-5.6-1.3-5.6-3.6 0-2 2.3-3.6 5.2-3.6 3-.3 5.6 1.3 5.6 3.6zm-31.1-4.5c-.7 2 1.3 4.3 4.3 4.9 2.6 1 5.6 0 6.2-2s-1.3-4.3-4.3-5.2c-2.6-.7-5.5 .3-6.2 2.3zm44.2-1.7c-2.9 .7-4.9 2.6-4.6 4.9 .3 2 2.9 3.3 5.9 2.6 2.9-.7 4.9-2.6 4.6-4.6-.3-1.9-3-3.2-5.9-2.9zM244.8 8C106.1 8 0 113.3 0 252c0 110.9 69.8 205.8 169.5 239.2 12.8 2.3 17.3-5.6 17.3-12.1 0-6.2-.3-40.4-.3-61.4 0 0-70 15-84.7-29.8 0 0-11.4-29.1-27.8-36.6 0 0-22.9-15.7 1.6-15.4 0 0 24.9 2 38.6 25.8 21.9 38.6 58.6 27.5 72.9 20.9 2.3-16 8.8-27.1 16-33.7-55.9-6.2-112.3-14.3-112.3-110.5 0-27.5 7.6-41.3 23.6-58.9-2.6-6.5-11.1-33.3 2.6-67.9 20.9-6.5 69 27 69 27 20-5.6 41.5-8.5 62.8-8.5s42.8 2.9 62.8 8.5c0 0 48.1-33.6 69-27 13.7 34.7 5.2 61.4 2.6 67.9 16 17.7 25.8 31.5 25.8 58.9 0 96.5-58.9 104.2-114.8 110.5 9.2 7.9 17 22.9 17 46.4 0 33.7-.3 75.4-.3 83.6 0 6.5 4.6 14.4 17.3 12.1C428.2 457.8 496 362.9 496 252 496 113.3 383.5 8 244.8 8zM97.2 352.9c-1.3 1-1 3.3 .7 5.2 1.6 1.6 3.9 2.3 5.2 1 1.3-1 1-3.3-.7-5.2-1.6-1.6-3.9-2.3-5.2-1zm-10.8-8.1c-.7 1.3 .3 2.9 2.3 3.9 1.6 1 3.6 .7 4.3-.7 .7-1.3-.3-2.9-2.3-3.9-2-.6-3.6-.3-4.3 .7zm32.4 35.6c-1.6 1.3-1 4.3 1.3 6.2 2.3 2.3 5.2 2.6 6.5 1 1.3-1.3 .7-4.3-1.3-6.2-2.2-2.3-5.2-2.6-6.5-1zm-11.4-14.7c-1.6 1-1.6 3.6 0 5.9 1.6 2.3 4.3 3.3 5.6 2.3 1.6-1.3 1.6-3.9 0-6.2-1.4-2.3-4-3.3-5.6-2z"/> 97 + </svg> 98 + </figure> 99 + <span class="social-label">Hann8n</span> 100 + </a> 101 + </li> 102 + <li> 103 + <a rel="noopener noreferrer external" target="_blank" class="social-link" href="https://www.instagram.com/yakyakjack_" title="Instagram: yakyakjack_"> 104 + <figure class="social-icon-wrapper"> 105 + <svg class="social-icon" focusable="false" role="img" viewBox="-0.5 -0.5 25 25" aria-hidden="true"> 106 + <path fill="currentColor" d="M7.03.084c-1.277.06-2.149.264-2.91.563a5.9 5.9 0 0 0-2.124 1.388a5.9 5.9 0 0 0-1.38 2.127C.321 4.926.12 5.8.064 7.076s-.069 1.688-.063 4.947s.021 3.667.083 4.947c.061 1.277.264 2.149.563 2.911c.308.789.72 1.457 1.388 2.123a5.9 5.9 0 0 0 2.129 1.38c.763.295 1.636.496 2.913.552c1.278.056 1.689.069 4.947.063s3.668-.021 4.947-.082c1.28-.06 2.147-.265 2.91-.563a5.9 5.9 0 0 0 2.123-1.388a5.9 5.9 0 0 0 1.38-2.129c.295-.763.496-1.636.551-2.912c.056-1.28.07-1.69.063-4.948c-.006-3.258-.02-3.667-.081-4.947c-.06-1.28-.264-2.148-.564-2.911a5.9 5.9 0 0 0-1.387-2.123a5.9 5.9 0 0 0-2.128-1.38c-.764-.294-1.636-.496-2.914-.55C15.647.009 15.236-.006 11.977 0S8.31.021 7.03.084m.14 21.693c-1.17-.05-1.805-.245-2.228-.408a3.7 3.7 0 0 1-1.382-.895a3.7 3.7 0 0 1-.9-1.378c-.165-.423-.363-1.058-.417-2.228c-.06-1.264-.072-1.644-.08-4.848c-.006-3.204.006-3.583.061-4.848c.05-1.169.246-1.805.408-2.228c.216-.561.477-.96.895-1.382a3.7 3.7 0 0 1 1.379-.9c.423-.165 1.057-.361 2.227-.417c1.265-.06 1.644-.072 4.848-.08c3.203-.006 3.583.006 4.85.062c1.168.05 1.804.244 2.227.408c.56.216.96.475 1.382.895s.681.817.9 1.378c.165.422.362 1.056.417 2.227c.06 1.265.074 1.645.08 4.848c.005 3.203-.006 3.583-.061 4.848c-.051 1.17-.245 1.805-.408 2.23c-.216.56-.477.96-.896 1.38a3.7 3.7 0 0 1-1.378.9c-.422.165-1.058.362-2.226.418c-1.266.06-1.645.072-4.85.079s-3.582-.006-4.848-.06m9.783-16.192a1.44 1.44 0 1 0 1.437-1.442a1.44 1.44 0 0 0-1.437 1.442M5.839 12.012a6.161 6.161 0 1 0 12.323-.024a6.162 6.162 0 0 0-12.323.024M8 12.008A4 4 0 1 1 12.008 16A4 4 0 0 1 8 12.008"/> 107 + </svg> 108 + </figure> 109 + <span class="social-label">yakyakjack_</span> 110 + </a> 111 + </li> 112 + <li> 113 + <a rel="noopener noreferrer external" target="_blank" class="social-link" href="https://bsky.app/profile/jack.orbyt.video" title="Bluesky: jack.orbyt.video"> 114 + <figure class="social-icon-wrapper"> 115 + <svg class="social-icon" focusable="false" role="img" viewBox="0 0 512 512" aria-hidden="true"> 116 + <path d="M111.8 62.2C170.2 105.9 233 194.7 256 242.4c23-47.6 85.8-136.4 144.2-180.2c42.1-31.6 110.3-56 110.3 21.8c0 15.5-8.9 130.5-14.1 149.2C478.2 298 412 314.6 353.1 304.5c102.9 17.5 129.1 75.5 72.5 133.5c-107.4 110.2-154.3-27.6-166.3-62.9l0 0c-1.7-4.9-2.6-7.8-3.3-7.8s-1.6 3-3.3 7.8l0 0c-12 35.3-59 173.1-166.3 62.9c-56.5-58-30.4-116 72.5-133.5C100 314.6 33.8 298 15.7 233.1C10.4 214.4 1.5 99.4 1.5 83.9c0-77.8 68.2-53.4 110.3-21.8z"/> 117 + </svg> 118 + </figure> 119 + <span class="social-label">jack.orbyt.video</span> 120 + </a> 121 + </li> 122 + <li> 123 + <a rel="noopener noreferrer external" target="_blank" class="social-link" href="https://getorbyt.com/@jack.orbyt.video" title="Orbyt: @jack"> 124 + <figure class="social-icon-wrapper"> 125 + <img src="images/orbyt-icon.png" alt="" class="social-icon orbyt-icon" aria-hidden="true"> 126 + </figure> 127 + <span class="social-label">@jack</span> 128 + </a> 129 + </li> 130 + <li> 131 + <a rel="noopener noreferrer" target="_blank" class="social-link" href="Jack_Hannon__Resume_Web.pdf" title="Resume"> 132 + <figure class="social-icon-wrapper"> 133 + <svg class="social-icon" focusable="false" role="img" viewBox="0 0 24 24" aria-hidden="true"> 134 + <path fill="currentColor" fill-rule="evenodd" d="M4.172 3.172C3 4.343 3 6.229 3 10v4c0 3.771 0 5.657 1.172 6.828S7.229 22 11 22h2c3.771 0 5.657 0 6.828-1.172S21 17.771 21 14v-4c0-3.771 0-5.657-1.172-6.828S16.771 2 13 2h-2C7.229 2 5.343 2 4.172 3.172M7.25 8A.75.75 0 0 1 8 7.25h8a.75.75 0 0 1 0 1.5H8A.75.75 0 0 1 7.25 8m0 4a.75.75 0 0 1 .75-.75h8a.75.75 0 0 1 0 1.5H8a.75.75 0 0 1-.75-.75M8 15.25a.75.75 0 0 0 0 1.5h5a.75.75 0 0 0 0-1.5z" clip-rule="evenodd"/> 135 + </svg> 136 + </figure> 137 + <span class="social-label">Resume</span> 138 + </a> 139 + </li> 140 + </ul> 141 + </section> 102 142 </div> 103 - </section> 143 + </div> 104 144 </main> 105 - <script> 106 - // Mobile nav toggle functionality (brand/menu swap) 107 - document.addEventListener('DOMContentLoaded', function() { 108 - const navToggle = document.querySelector('.mobile-nav-toggle'); 109 - const brand = document.getElementById('brand'); 110 - const menu = document.getElementById('main-menu'); 111 - const headerControls = document.getElementById('header-controls'); 112 - function isMobile() { 113 - return window.innerWidth <= 650; 114 - } 115 - function showMenuInBar(show) { 116 - if (isMobile()) { 117 - if (show) { 118 - brand.style.display = 'none'; 119 - menu.style.display = 'flex'; 120 - menu.classList.add('menu-in-bar'); 121 - } else { 122 - brand.style.display = ''; 123 - menu.style.display = ''; 124 - menu.classList.remove('menu-in-bar'); 125 - } 126 - } else { 127 - brand.style.display = ''; 128 - menu.style.display = ''; 129 - menu.classList.remove('menu-in-bar'); 130 - } 131 - } 132 - if (navToggle && brand && menu) { 133 - navToggle.addEventListener('click', function() { 134 - const expanded = navToggle.getAttribute('aria-expanded') === 'true'; 135 - navToggle.setAttribute('aria-expanded', !expanded); 136 - showMenuInBar(!expanded); 137 - }); 138 - window.addEventListener('resize', function() { 139 - // Reset on resize 140 - if (!isMobile()) { 141 - showMenuInBar(false); 142 - navToggle.setAttribute('aria-expanded', false); 143 - } 144 - }); 145 - } 146 - }); 147 - </script> 148 - <script src="script.js"></script> 149 145 </body> 150 146 </html>
-87
privacy-policy.html
··· 1 - <!DOCTYPE html> 2 - <html lang="en"> 3 - <head> 4 - <meta charset="UTF-8" /> 5 - <meta name="viewport" content="width=device-width, initial-scale=1.0" /> 6 - <title>Privacy Policy | Jack Hannon</title> 7 - <script> 8 - // Apply saved theme or OS preference before CSS loads to prevent flash 9 - if (localStorage.getItem('theme') === 'dark' || 10 - (!localStorage.getItem('theme') && window.matchMedia('(prefers-color-scheme: dark)').matches)) { 11 - document.documentElement.classList.add('dark-theme'); 12 - } 13 - </script> 14 - <link rel="stylesheet" href="style.css" /> 15 - <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@20..48,100..700,0..1,-50..200&icon_names=match_case" /> 16 - <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css" /> 17 - <style> 18 - .material-symbols-outlined { 19 - font-variation-settings: 20 - 'FILL' 0, 21 - 'wght' 400, 22 - 'GRAD' 0, 23 - 'opsz' 24 24 - } 25 - </style> 26 - </head> 27 - <body> 28 - <main class="container" id="main-content"> 29 - <div id="a11y-status" class="visually-hidden" aria-live="polite" aria-atomic="true"></div> 30 - 31 - <section class="privacy-policy"> 32 - <div class="app-icon-container"> 33 - <a href="https://apps.apple.com/us/app/vt-gym-tracker/id6736409867?itscg=30200&itsct=apps_box_link&mttnsubad=6736409867" 34 - target="_blank" 35 - rel="noopener noreferrer" 36 - aria-label="Download VT Gym Tracker on the App Store"> 37 - <img src="images/VT-Gym-Tracker-ios-Icon.png" 38 - alt="VT Gym Tracker App Icon" 39 - class="app-icon" 40 - width="140" 41 - height="140" 42 - loading="eager" 43 - decoding="async" /> 44 - </a> 45 - </div> 46 - <h1>Privacy Policy</h1> 47 - <p><strong>Last Updated:</strong> January 11, 2025</p> 48 - 49 - <p>Jack Hannon [I, Me, My] built Gym Tracker (the "App") as a free, non-commercial application. The App and any additional services provided now or in the future are provided "as is." This Privacy Policy outlines how I handle your information when you use my mobile application, Gym Tracker. By accessing or using the App, you agree to these privacy terms.</p> 50 - 51 - <h2>Information Collected</h2> 52 - <p>Gym Tracker does not collect, store, or transmit any personal or non-personal information from its users. Any data saved in the app is stored locally on the device.</p> 53 - 54 - <h2>Third-Party Services</h2> 55 - <p>The App connects to the Virginia Tech Recreational Sports website ("VT Rec Sports"). VT Rec Sports and their partners may collect personal information as outlined in their Privacy Policy. I encourage you to review their policy to understand how your information is handled when you interact with VT Rec Sports through the App.</p> 56 - 57 - <h2>Links to Third-Party Websites</h2> 58 - <p>The App may contain links to third-party websites or services that I don't operate. Once you leave the App, I have no control over these external sites and cannot be responsible for their privacy practices. Please review the privacy policies of any third-party sites you visit.</p> 59 - 60 - <h2>Changes to This Privacy Policy</h2> 61 - <p>I may update this Privacy Policy periodically. Any changes will be posted on this page with an updated "Last Updated" date.</p> 62 - 63 - <h2>Contact</h2> 64 - <p>If you have any questions or suggestions about this Privacy Policy, please contact me at <a href="mailto:hannon@vt.edu">hannon@vt.edu</a></p> 65 - </section> 66 - </main> 67 - 68 - <div class="social-icons"> 69 - <a href="https://www.linkedin.com/in/jackphannon/" target="_blank" rel="noopener noreferrer" aria-label="LinkedIn Profile"> 70 - <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512" class="linkedin-icon"> 71 - <path d="M416 32H31.9C14.3 32 0 46.5 0 64.3v383.4C0 465.5 14.3 480 31.9 480H416c17.6 0 32-14.5 32-32.3V64.3c0-17.8-14.4-32.3-32-32.3zM135.4 416H69V202.2h66.5V416zm-33.2-243c-21.3 0-38.5-17.3-38.5-38.5S80.9 96 102.2 96c21.2 0 38.5 17.3 38.5 38.5 0 21.3-17.2 38.5-38.5 38.5zm282.1 243h-66.4V312c0-24.8-.5-56.7-34.5-56.7-34.6 0-39.9 27-39.9 54.9V416h-66.4V202.2h63.7v29.2h.9c8.9-16.8 30.6-34.5 62.9-34.5 67.2 0 79.7 44.3 79.7 101.9V416z"/> 72 - </svg> 73 - </a> 74 - <a href="https://github.com/Hann8n" target="_blank" rel="noopener noreferrer" aria-label="GitHub Profile"> 75 - <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 496 512" class="github-icon"> 76 - <path d="M165.9 397.4c0 2-2.3 3.6-5.2 3.6-3.3 .3-5.6-1.3-5.6-3.6 0-2 2.3-3.6 5.2-3.6 3-.3 5.6 1.3 5.6 3.6zm-31.1-4.5c-.7 2 1.3 4.3 4.3 4.9 2.6 1 5.6 0 6.2-2s-1.3-4.3-4.3-5.2c-2.6-.7-5.5 .3-6.2 2.3zm44.2-1.7c-2.9 .7-4.9 2.6-4.6 4.9 .3 2 2.9 3.3 5.9 2.6 2.9-.7 4.9-2.6 4.6-4.6-.3-1.9-3-3.2-5.9-2.9zM244.8 8C106.1 8 0 113.3 0 252c0 110.9 69.8 205.8 169.5 239.2 12.8 2.3 17.3-5.6 17.3-12.1 0-6.2-.3-40.4-.3-61.4 0 0-70 15-84.7-29.8 0 0-11.4-29.1-27.8-36.6 0 0-22.9-15.7 1.6-15.4 0 0 24.9 2 38.6 25.8 21.9 38.6 58.6 27.5 72.9 20.9 2.3-16 8.8-27.1 16-33.7-55.9-6.2-112.3-14.3-112.3-110.5 0-27.5 7.6-41.3 23.6-58.9-2.6-6.5-11.1-33.3 2.6-67.9 20.9-6.5 69 27 69 27 20-5.6 41.5-8.5 62.8-8.5s42.8 2.9 62.8 8.5c0 0 48.1-33.6 69-27 13.7 34.7 5.2 61.4 2.6 67.9 16 17.7 25.8 31.5 25.8 58.9 0 96.5-58.9 104.2-114.8 110.5 9.2 7.9 17 22.9 17 46.4 0 33.7-.3 75.4-.3 83.6 0 6.5 4.6 14.4 17.3 12.1C428.2 457.8 496 362.9 496 252 496 113.3 383.5 8 244.8 8zM97.2 352.9c-1.3 1-1 3.3 .7 5.2 1.6 1.6 3.9 2.3 5.2 1 1.3-1 1-3.3-.7-5.2-1.6-1.6-3.9-2.3-5.2-1zm-10.8-8.1c-.7 1.3 .3 2.9 2.3 3.9 1.6 1 3.6 .7 4.3-.7 .7-1.3-.3-2.9-2.3-3.9-2-.6-3.6-.3-4.3 .7zm32.4 35.6c-1.6 1.3-1 4.3 1.3 6.2 2.3 2.3 5.2 2.6 6.5 1 1.3-1.3 .7-4.3-1.3-6.2-2.2-2.3-5.2-2.6-6.5-1zm-11.4-14.7c-1.6 1-1.6 3.6 0 5.9 1.6 2.3 4.3 3.3 5.6 2.3 1.6-1.3 1.6-3.9 0-6.2-1.4-2.3-4-3.3-5.6-2z"/> 77 - </svg> 78 - </a> 79 - <a href="https://bsky.app/profile/jackhannon.me" target="_blank" rel="noopener noreferrer" aria-label="Bluesky Profile"> 80 - <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" class="bluesky-icon"> 81 - <path d="M111.8 62.2C170.2 105.9 233 194.7 256 242.4c23-47.6 85.8-136.4 144.2-180.2c42.1-31.6 110.3-56 110.3 21.8c0 15.5-8.9 130.5-14.1 149.2C478.2 298 412 314.6 353.1 304.5c102.9 17.5 129.1 75.5 72.5 133.5c-107.4 110.2-154.3-27.6-166.3-62.9l0 0c-1.7-4.9-2.6-7.8-3.3-7.8s-1.6 3-3.3 7.8l0 0c-12 35.3-59 173.1-166.3 62.9c-56.5-58-30.4-116 72.5-133.5C100 314.6 33.8 298 15.7 233.1C10.4 214.4 1.5 99.4 1.5 83.9c0-77.8 68.2-53.4 110.3-21.8z"/> 82 - </svg> 83 - </a> 84 - </div> 85 - <script src="script.js"></script> 86 - </body> 87 - </html>
-79
privacy.html
··· 1 - <!DOCTYPE html> 2 - <html lang="en"> 3 - <head> 4 - <meta charset="UTF-8" /> 5 - <meta name="viewport" content="width=device-width, initial-scale=1.0" /> 6 - <title>Privacy Policy | Jack Hannon</title> 7 - <script> 8 - // Apply saved theme or OS preference before CSS loads to prevent flash 9 - if (localStorage.getItem('theme') === 'dark' || 10 - (!localStorage.getItem('theme') && window.matchMedia('(prefers-color-scheme: dark)').matches)) { 11 - document.documentElement.classList.add('dark-theme'); 12 - } 13 - </script> 14 - <link rel="stylesheet" href="style.css" /> 15 - <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@20..48,100..700,0..1,-50..200&icon_names=match_case" /> 16 - <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css" /> 17 - <style> 18 - .material-symbols-outlined { 19 - font-variation-settings: 20 - 'FILL' 0, 21 - 'wght' 400, 22 - 'GRAD' 0, 23 - 'opsz' 24 24 - } 25 - </style> 26 - </head> 27 - <body> 28 - <main class="container" id="main-content"> 29 - <div id="a11y-status" class="visually-hidden" aria-live="polite" aria-atomic="true"></div> 30 - 31 - <section class="privacy-policy"> 32 - <h1>Privacy Policy</h1> 33 - <p><strong>Last Updated:</strong> January 11, 2025</p> 34 - 35 - <p>Jack Hannon [I, Me, My] built Gym Tracker (the "App") as a free, non-commercial application. The App and any additional services provided now or in the future are provided "as is." This Privacy Policy outlines how I handle your information when you use my mobile application, Gym Tracker. By accessing or using the App, you agree to these privacy terms.</p> 36 - 37 - <h2>Information Collected</h2> 38 - <p>Gym Tracker does not collect, store, or transmit any personal or non-personal information from its users. Any data saved in the app is stored locally on the device.</p> 39 - 40 - <h2>Third-Party Services</h2> 41 - <p>The App connects to the Virginia Tech Recreational Sports website ("VT Rec Sports"). VT Rec Sports and their partners may collect personal information as outlined in their Privacy Policy. I encourage you to review their policy to understand how your information is handled when you interact with VT Rec Sports through the App.</p> 42 - 43 - <h2>Links to Third-Party Websites</h2> 44 - <p>The App may contain links to third-party websites or services that I don't operate. Once you leave the App, I have no control over these external sites and cannot be responsible for their privacy practices. Please review the privacy policies of any third-party sites you visit.</p> 45 - 46 - <h2>Changes to This Privacy Policy</h2> 47 - <p>I may update this Privacy Policy periodically. Any changes will be posted on this page with an updated "Last Updated" date.</p> 48 - 49 - <h2>Contact</h2> 50 - <p>If you have any questions or suggestions about this Privacy Policy, please contact me at <a href="mailto:hannon@vt.edu">hannon@vt.edu</a></p> 51 - </section> 52 - </main> 53 - 54 - <footer class="privacy-footer"> 55 - <div class="container"> 56 - <div class="footer-content"> 57 - <div class="footer-social"> 58 - <a href="https://www.linkedin.com/in/jackphannon/" target="_blank" rel="noopener noreferrer" aria-label="LinkedIn Profile"> 59 - <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512" class="linkedin-icon"> 60 - <path d="M416 32H31.9C14.3 32 0 46.5 0 64.3v383.4C0 465.5 14.3 480 31.9 480H416c17.6 0 32-14.5 32-32.3V64.3c0-17.8-14.4-32.3-32-32.3zM135.4 416H69V202.2h66.5V416zm-33.2-243c-21.3 0-38.5-17.3-38.5-38.5S80.9 96 102.2 96c21.2 0 38.5 17.3 38.5 38.5 0 21.3-17.2 38.5-38.5 38.5zm282.1 243h-66.4V312c0-24.8-.5-56.7-34.5-56.7-34.6 0-39.9 27-39.9 54.9V416h-66.4V202.2h63.7v29.2h.9c8.9-16.8 30.6-34.5 62.9-34.5 67.2 0 79.7 44.3 79.7 101.9V416z"/> 61 - </svg> 62 - </a> 63 - <a href="https://github.com/Hann8n" target="_blank" rel="noopener noreferrer" aria-label="GitHub Profile"> 64 - <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 496 512" class="github-icon"> 65 - <path d="M165.9 397.4c0 2-2.3 3.6-5.2 3.6-3.3 .3-5.6-1.3-5.6-3.6 0-2 2.3-3.6 5.2-3.6 3-.3 5.6 1.3 5.6 3.6zm-31.1-4.5c-.7 2 1.3 4.3 4.3 4.9 2.6 1 5.6 0 6.2-2s-1.3-4.3-4.3-5.2c-2.6-.7-5.5 .3-6.2 2.3zm44.2-1.7c-2.9 .7-4.9 2.6-4.6 4.9 .3 2 2.9 3.3 5.9 2.6 2.9-.7 4.9-2.6 4.6-4.6-.3-1.9-3-3.2-5.9-2.9zM244.8 8C106.1 8 0 113.3 0 252c0 110.9 69.8 205.8 169.5 239.2 12.8 2.3 17.3-5.6 17.3-12.1 0-6.2-.3-40.4-.3-61.4 0 0-70 15-84.7-29.8 0 0-11.4-29.1-27.8-36.6 0 0-22.9-15.7 1.6-15.4 0 0 24.9 2 38.6 25.8 21.9 38.6 58.6 27.5 72.9 20.9 2.3-16 8.8-27.1 16-33.7-55.9-6.2-112.3-14.3-112.3-110.5 0-27.5 7.6-41.3 23.6-58.9-2.6-6.5-11.1-33.3 2.6-67.9 20.9-6.5 69 27 69 27 20-5.6 41.5-8.5 62.8-8.5s42.8 2.9 62.8 8.5c0 0 48.1-33.6 69-27 13.7 34.7 5.2 61.4 2.6 67.9 16 17.7 25.8 31.5 25.8 58.9 0 96.5-58.9 104.2-114.8 110.5 9.2 7.9 17 22.9 17 46.4 0 33.7-.3 75.4-.3 83.6 0 6.5 4.6 14.4 17.3 12.1C428.2 457.8 496 362.9 496 252 496 113.3 383.5 8 244.8 8zM97.2 352.9c-1.3 1-1 3.3 .7 5.2 1.6 1.6 3.9 2.3 5.2 1 1.3-1 1-3.3-.7-5.2-1.6-1.6-3.9-2.3-5.2-1zm-10.8-8.1c-.7 1.3 .3 2.9 2.3 3.9 1.6 1 3.6 .7 4.3-.7 .7-1.3-.3-2.9-2.3-3.9-2-.6-3.6-.3-4.3 .7zm32.4 35.6c-1.6 1.3-1 4.3 1.3 6.2 2.3 2.3 5.2 2.6 6.5 1 1.3-1.3 .7-4.3-1.3-6.2-2.2-2.3-5.2-2.6-6.5-1zm-11.4-14.7c-1.6 1-1.6 3.6 0 5.9 1.6 2.3 4.3 3.3 5.6 2.3 1.6-1.3 1.6-3.9 0-6.2-1.4-2.3-4-3.3-5.6-2z"/> 66 - </svg> 67 - </a> 68 - <a href="https://bsky.app/profile/jackhannon.me" target="_blank" rel="noopener noreferrer" aria-label="Bluesky Profile"> 69 - <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" class="bluesky-icon"> 70 - <path d="M111.8 62.2C170.2 105.9 233 194.7 256 242.4c23-47.6 85.8-136.4 144.2-180.2c42.1-31.6 110.3-56 110.3 21.8c0 15.5-8.9 130.5-14.1 149.2C478.2 298 412 314.6 353.1 304.5c102.9 17.5 129.1 75.5 72.5 133.5c-107.4 110.2-154.3-27.6-166.3-62.9l0 0c-1.7-4.9-2.6-7.8-3.3-7.8s-1.6 3-3.3 7.8l0 0c-12 35.3-59 173.1-166.3 62.9c-56.5-58-30.4-116 72.5-133.5C100 314.6 33.8 298 15.7 233.1C10.4 214.4 1.5 99.4 1.5 83.9c0-77.8 68.2-53.4 110.3-21.8z"/> 71 - </svg> 72 - </a> 73 - </div> 74 - </div> 75 - </div> 76 - </footer> 77 - <script src="script.js"></script> 78 - </body> 79 - </html>
-262
projects.html
··· 1 - <!DOCTYPE html> 2 - <html lang="en"> 3 - <head> 4 - <meta charset="UTF-8" /> 5 - <meta name="viewport" content="width=device-width, initial-scale=1.0" /> 6 - <title>Jack Hannon | Projects</title> 7 - <script> 8 - if (localStorage.getItem('theme') === 'dark' || 9 - (!localStorage.getItem('theme') && window.matchMedia('(prefers-color-scheme: dark)').matches)) { 10 - document.documentElement.classList.add('dark-theme'); 11 - } 12 - </script> 13 - <link rel="stylesheet" href="style.css" /> 14 - <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@20..48,100..700,0..1,-50..200&icon_names=match_case" /> 15 - <style> 16 - .material-symbols-outlined { 17 - font-variation-settings: 18 - 'FILL' 0, 19 - 'wght' 400, 20 - 'GRAD' 0, 21 - 'opsz' 24 22 - } 23 - </style> 24 - </head> 25 - <body> 26 - <a href="#main-content" class="skip-link">Skip to main content</a> 27 - <header> 28 - <nav class="container" role="navigation" aria-label="Main navigation" style="display: flex; align-items: center; justify-content: space-between;"> 29 - <a href="index.html" class="brand" id="brand">Jack Hannon</a> 30 - <div class="header-controls" id="header-controls" style="margin-left: auto; display: flex; align-items: center;"> 31 - <button class="mobile-nav-toggle" aria-controls="header-controls" aria-expanded="false" aria-label="Open navigation menu"> 32 - <span class="hamburger-icon"></span> 33 - </button> 34 - <ul class="menu" role="menubar" id="main-menu"> 35 - <li><a href="index.html" role="menuitem" tabindex="0">About</a></li> 36 - <li><a href="projects.html" class="active" role="menuitem" tabindex="0">Projects</a></li> 37 - <li><a href="resume.html" role="menuitem" tabindex="0">Resume</a></li> 38 - </ul> 39 - <div class="header-divider"></div> 40 - <span id="accessibility-btn" class="accessibility-icon" aria-label="Accessibility options" aria-haspopup="true" aria-expanded="false" tabindex="0"> 41 - <span class="material-symbols-outlined" aria-hidden="true">match_case</span> 42 - </span> 43 - <div id="accessibility-menu" class="accessibility-menu" style="display:none;" role="menu" aria-label="Accessibility options"> 44 - <div class="access-section"> 45 - <div class="access-label">Theme</div> 46 - <div class="access-theme-btns"> 47 - <label class="access-radio"><input type="radio" name="theme-mode" value="system" /> System</label> 48 - <label class="access-radio"><input type="radio" name="theme-mode" value="light" /> Light</label> 49 - <label class="access-radio"><input type="radio" name="theme-mode" value="dark" /> Dark</label> 50 - </div> 51 - </div> 52 - <div class="access-section"> 53 - <label class="access-toggle"><input type="checkbox" id="high-contrast-toggle" /> High Contrast</label> 54 - </div> 55 - <div class="access-section access-textsize"> 56 - <div class="access-label">Text Size</div> 57 - <div class="access-textsize-btns"> 58 - <button type="button" id="text-decrease" class="textsize-round" aria-label="Decrease text size">–</button> 59 - <span id="text-reset" class="textsize-reset" tabindex="0" role="button" aria-label="Reset text size">Reset</span> 60 - <button type="button" id="text-increase" class="textsize-round" aria-label="Increase text size">+</button> 61 - </div> 62 - </div> 63 - </div> 64 - </div> 65 - </nav> 66 - </header> 67 - <main class="container projects-main" id="main-content"> 68 - <div id="a11y-status" class="visually-hidden" aria-live="polite" aria-atomic="true"></div> 69 - <h1>Projects</h1> 70 - <section> 71 - <h2>VT Gym Tracker <small>(Independent Developer, 2024)</small></h2> 72 - <p> 73 - Developed and launched a mobile app for Virginia Tech campus gyms that provides real-time occupancy data and schedules. 74 - Created a marketing campaign to drive user adoption during the app's App Store release. 75 - </p> 76 - 77 - <div class="ios-app-showcase"> 78 - <div class="showcase-content"> 79 - <h3>VT Gym Tracker</h3> 80 - <p class="app-description"> 81 - A native iOS app that helps Virginia Tech students track real-time gym occupancy, 82 - view facility hours, and plan their workouts efficiently. Built with SwiftUI and 83 - integrated with campus data systems. 84 - </p> 85 - 86 - 87 - 88 - <!-- App Screenshots Horizontal List --> 89 - <div class="app-screenshots" id="app-screenshots" role="region" aria-label="VT Gym Tracker screenshots"> 90 - <div class="screenshot-item"> 91 - <img src="images/vt-gym-Data.png" alt="VT Gym Tracker: Data screen showing real-time occupancy" loading="lazy" /> 92 - </div> 93 - <div class="screenshot-item"> 94 - <img src="images/vt-gym-hours.png" alt="VT Gym Tracker: Hours screen showing facility schedules" loading="lazy" /> 95 - </div> 96 - <div class="screenshot-item"> 97 - <img src="images/vt-gym-widgets.png" alt="VT Gym Tracker: Widgets screen showing quick access features" loading="lazy" /> 98 - </div> 99 - </div> 100 - 101 - <!-- App Features --> 102 - <div class="app-features"> 103 - <div class="feature-card"> 104 - <h4>Real-time Data</h4> 105 - <p>Live occupancy tracking for all campus gym facilities with minute-by-minute updates</p> 106 - </div> 107 - <div class="feature-card"> 108 - <h4>Widget Support</h4> 109 - <p>Quick access widgets for instant gym status without opening the app</p> 110 - </div> 111 - </div> 112 - 113 - <!-- App Stats --> 114 - <div class="app-stats"> 115 - <div class="stat-item"> 116 - <span class="stat-number">1k+</span> 117 - <span class="stat-label">Active Users</span> 118 - </div> 119 - <div class="stat-item"> 120 - <span class="stat-number">5.0 ★</span> 121 - <span class="stat-label">App Store Rating</span> 122 - </div> 123 - </div> 124 - 125 - <!-- App Store Link --> 126 - <div class="app-store-section"> 127 - <a href="https://apps.apple.com/us/app/vt-gym-tracker/id6736409867?itscg=30200&itsct=apps_box_badge&mttnsubad=6736409867" 128 - class="app-store-badge" target="_blank" rel="noopener noreferrer"> 129 - <img src="https://toolbox.marketingtools.apple.com/api/v2/badges/download-on-the-app-store/black/en-us?releaseDate=1737590400" 130 - alt="Download VT Gym Tracker on the App Store" /> 131 - </a> 132 - </div> 133 - </div> 134 - </div> 135 - </section> 136 - <section> 137 - <h2>Yik Yak Virginia Tech <small>(Social Media Manager, 2022–2024)</small></h2> 138 - <p> 139 - Managed the official Yik Yak Virginia Tech social media presence, creating engaging content and fostering community engagement. 140 - Developed templates and content strategies for other university accounts in the program. 141 - </p> 142 - 143 - <div class="vt-yikyak-showcase"> 144 - <div class="showcase-content"> 145 - <!-- Profile Picture and Title --> 146 - <div class="profile-header"> 147 - <img src="images/yikyak-profile.jpg" alt="Yik Yak Virginia Tech profile picture" class="profile-picture" loading="lazy" /> 148 - <div class="title-section"> 149 - <h3>Yik Yak Virginia Tech</h3> 150 - <p class="subtitle">@yikyakvtech</p> 151 - </div> 152 - </div> 153 - <p class="app-description"> 154 - Led social media management for the official Yik Yak Virginia Tech account, creating engaging content 155 - that resonated with the student community. Developed templates and strategies that were adopted by 156 - other university accounts in the Yik Yak program. 157 - </p> 158 - 159 - <!-- Top Posts Section --> 160 - <div class="content-section"> 161 - <h4 class="section-title-left">Top Posts</h4> 162 - <div class="static-image-section"> 163 - <p>Posting consistent and engaging content regularly has helped maintain and grow the page.</p> 164 - <img src="images/Yik Yak VT/YYVT-1.png" alt="Yik Yak Virginia Tech Top Posts" loading="lazy" class="rounded-image" style="max-width:100%;height:auto;" /> 165 - </div> 166 - </div> 167 - 168 - <!-- Event Posts Section --> 169 - <div class="content-section"> 170 - <h4 class="section-title-left">Event Posts</h4> 171 - <div class="static-image-section"> 172 - <p>Creating event specific content for the page to capitalize on increased engagement.</p> 173 - <img src="images/Yik Yak VT/YYVT-2.png" alt="Yik Yak Virginia Tech Event Posts" loading="lazy" class="rounded-image" style="max-width:100%;height:auto;" /> 174 - </div> 175 - </div> 176 - 177 - <!-- Templates Section --> 178 - <div class="content-section"> 179 - <h4 class="section-title-left">Content Templates</h4> 180 - <div class="static-image-section"> 181 - <p>I've created a few different post templates for other schools on Yik Yak. Post formats help establish a recognizable brand and create a more professional looking page.</p> 182 - <img src="images/Yik Yak VT/YYVT-3.png" alt="Yik Yak Virginia Tech Templates" loading="lazy" class="rounded-image" style="max-width:100%;height:auto;" /> 183 - </div> 184 - </div> 185 - 186 - <!-- Project Features --> 187 - <p><strong>Content Creation:</strong> Developed engaging social media content that increased community engagement and follower growth</p> 188 - <p><strong>Template Development:</strong> Created reusable content templates adopted by other university accounts in the Yik Yak program</p> 189 - <p><strong>Community Management:</strong> Fostered positive community interactions and maintained brand voice across all communications</p> 190 - 191 - <!-- Project Stats --> 192 - <div class="app-stats"> 193 - <div class="stat-item"> 194 - <span class="stat-number">2+</span> 195 - <span class="stat-label">Years Experience</span> 196 - </div> 197 - <div class="stat-item"> 198 - <span class="stat-number">3</span> 199 - <span class="stat-label">University Templates</span> 200 - </div> 201 - </div> 202 - </div> 203 - </div> 204 - </section> 205 - <section> 206 - <h2>Old Burying Ground Restoration Project <small>(Project Lead, 2019–2021)</small></h2> 207 - <p> 208 - In collaboration with <a href="https://www.allentownvinj.org" target="_blank" rel="noopener">The Allentown Village Initiative</a>, I led the restoration of a historic cemetery in Allentown, NJ. 209 - </p> 210 - <div class="project-media allentown-media"> 211 - <div class="carousel"> 212 - <img src="images/Troop-180A.png" alt="Troop-180A of Allentown, NJ" /> 213 - </div> 214 - </div> 215 - </section> 216 - </main> 217 - <script> 218 - // Mobile nav toggle functionality (brand/menu swap) 219 - document.addEventListener('DOMContentLoaded', function() { 220 - const navToggle = document.querySelector('.mobile-nav-toggle'); 221 - const brand = document.getElementById('brand'); 222 - const menu = document.getElementById('main-menu'); 223 - const headerControls = document.getElementById('header-controls'); 224 - function isMobile() { 225 - return window.innerWidth <= 600; 226 - } 227 - function showMenuInBar(show) { 228 - if (isMobile()) { 229 - if (show) { 230 - brand.style.display = 'none'; 231 - menu.style.display = 'flex'; 232 - menu.classList.add('menu-in-bar'); 233 - } else { 234 - brand.style.display = ''; 235 - menu.style.display = ''; 236 - menu.classList.remove('menu-in-bar'); 237 - } 238 - } else { 239 - brand.style.display = ''; 240 - menu.style.display = ''; 241 - menu.classList.remove('menu-in-bar'); 242 - } 243 - } 244 - if (navToggle && brand && menu) { 245 - navToggle.addEventListener('click', function() { 246 - const expanded = navToggle.getAttribute('aria-expanded') === 'true'; 247 - navToggle.setAttribute('aria-expanded', !expanded); 248 - showMenuInBar(!expanded); 249 - }); 250 - window.addEventListener('resize', function() { 251 - // Reset on resize 252 - if (!isMobile()) { 253 - showMenuInBar(false); 254 - navToggle.setAttribute('aria-expanded', false); 255 - } 256 - }); 257 - } 258 - }); 259 - </script> 260 - <script src="script.js"></script> 261 - </body> 262 - </html>
-192
resume.html
··· 1 - <!DOCTYPE html> 2 - <html lang="en"> 3 - <head> 4 - <meta charset="UTF-8" /> 5 - <meta name="viewport" content="width=device-width, initial-scale=1.0" /> 6 - <title>Jack Hannon | Resume</title> 7 - <script> 8 - if (localStorage.getItem('theme') === 'dark' || 9 - (!localStorage.getItem('theme') && window.matchMedia('(prefers-color-scheme: dark)').matches)) { 10 - document.documentElement.classList.add('dark-theme'); 11 - } 12 - </script> 13 - <link rel="stylesheet" href="style.css" /> 14 - <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@20..48,100..700,0..1,-50..200&icon_names=match_case" /> 15 - <style> 16 - .material-symbols-outlined { 17 - font-variation-settings: 18 - 'FILL' 0, 19 - 'wght' 400, 20 - 'GRAD' 0, 21 - 'opsz' 24 22 - } 23 - </style> 24 - </head> 25 - <body> 26 - <a href="#main-content" class="skip-link">Skip to main content</a> 27 - <header> 28 - <nav class="container" role="navigation" aria-label="Main navigation" style="display: flex; align-items: center; justify-content: space-between;"> 29 - <a href="index.html" class="brand" id="brand">Jack Hannon</a> 30 - <div class="header-controls" id="header-controls" style="margin-left: auto; display: flex; align-items: center;"> 31 - <button class="mobile-nav-toggle" aria-controls="header-controls" aria-expanded="false" aria-label="Open navigation menu"> 32 - <span class="hamburger-icon"></span> 33 - </button> 34 - <ul class="menu" role="menubar" id="main-menu"> 35 - <li><a href="index.html" role="menuitem" tabindex="0">About</a></li> 36 - <li><a href="projects.html" role="menuitem" tabindex="0">Projects</a></li> 37 - <li><a href="resume.html" class="active" role="menuitem" tabindex="0">Resume</a></li> 38 - </ul> 39 - <div class="header-divider"></div> 40 - <span id="accessibility-btn" class="accessibility-icon" aria-label="Accessibility options" aria-haspopup="true" aria-expanded="false" tabindex="0"> 41 - <span class="material-symbols-outlined" aria-hidden="true">match_case</span> 42 - </span> 43 - <div id="accessibility-menu" class="accessibility-menu" style="display:none;" role="menu" aria-label="Accessibility options"> 44 - <div class="access-section"> 45 - <div class="access-label">Theme</div> 46 - <div class="access-theme-btns"> 47 - <label class="access-radio"><input type="radio" name="theme-mode" value="system" /> System</label> 48 - <label class="access-radio"><input type="radio" name="theme-mode" value="light" /> Light</label> 49 - <label class="access-radio"><input type="radio" name="theme-mode" value="dark" /> Dark</label> 50 - </div> 51 - </div> 52 - <div class="access-section"> 53 - <label class="access-toggle"><input type="checkbox" id="high-contrast-toggle" /> High Contrast</label> 54 - </div> 55 - <div class="access-section access-textsize"> 56 - <div class="access-label">Text Size</div> 57 - <div class="access-textsize-btns"> 58 - <button type="button" id="text-decrease" class="textsize-round" aria-label="Decrease text size">–</button> 59 - <span id="text-reset" class="textsize-reset" tabindex="0" role="button" aria-label="Reset text size">Reset</span> 60 - <button type="button" id="text-increase" class="textsize-round" aria-label="Increase text size">+</button> 61 - </div> 62 - </div> 63 - </div> 64 - </div> 65 - </nav> 66 - </header> 67 - <main class="container resume-main" id="main-content"> 68 - <div id="a11y-status" class="visually-hidden" aria-live="polite" aria-atomic="true"></div> 69 - <div class="resume-header"> 70 - <h1>Resume</h1> 71 - <a href="Jack_Hannon_Marketing_Resume_Web.pdf" class="btn pdf-btn" download aria-label="Download Jack Hannon's resume as PDF">Download PDF</a> 72 - </div> 73 - 74 - 75 - 76 - <section> 77 - <h2>Education</h2> 78 - <h3>Virginia Tech, Blacksburg, VA</h3> 79 - <p>Bachelor of Arts in Advertising, Minor in Organizational Leadership | May 2025</p> 80 - </section> 81 - 82 - <section> 83 - <h2>Skills</h2> 84 - <h3>Communication & Customer Service:</h3> 85 - <ul> 86 - <li>- Excellent written and verbal skills; adept at crafting engaging correspondence with a customer-first mindset.</li> 87 - </ul> 88 - 89 - <h3>Technical Proficiency:</h3> 90 - <ul> 91 - <li>- Proficient in Google Ads, Adobe Creative Suite, Meta Business Suite, HubSpot CRM; familiar with Mailchimp, HubSpot, WordPress, and Google Analytics.</li> 92 - </ul> 93 - 94 - <h3>Community Engagement:</h3> 95 - <ul> 96 - <li>- Experience in community outreach, event coordination, and audience engagement strategies.</li> 97 - </ul> 98 - </section> 99 - 100 - <section> 101 - <h2>Experience</h2> 102 - <h3>Campus Ambassador, Yik Yak <small>(February 2022 – February 2024)</small></h3> 103 - <ul> 104 - <li>- Represented Yik Yak at Virginia Tech online and through local campaigns</li> 105 - <li>- Organized on-campus events</li> 106 - <li>- Collected user feedback</li> 107 - </ul> 108 - 109 - <h3>Recreation Assistant, Christiansburg Dept. of Parks and Recreation <small>(October 2023 – May 2025)</small></h3> 110 - <ul> 111 - <li>- Provided customer service to park patrons and local sports leagues</li> 112 - <li>- Supported event setup and facility operations</li> 113 - <li>- Helped ensure adherence to department guidelines and safety standards</li> 114 - </ul> 115 - 116 - <h3>Store Clerk, Party City PCHI <small>(May 2023 – August 2023)</small></h3> 117 - <ul> 118 - <li>- Aided event planning, including logistics for balloon arrangements and party supplies</li> 119 - <li>- Fulfilled online merchandise and balloon orders</li> 120 - <li>- Handled checkout, inventory, and customer concerns</li> 121 - <li>- Maintained store organization and product displays</li> 122 - </ul> 123 - </section> 124 - 125 - <section> 126 - <h2>Projects</h2> 127 - <h3>Project Lead, The Allentown Village Initiative <small>(August 2019 – July 2021)</small></h3> 128 - <ul> 129 - <li>- Led a community service project restoring a historic cemetery</li> 130 - <li>- Organized volunteers and coordinated with local officials</li> 131 - </ul> 132 - 133 - <h3>Independent Developer, VT Gym Tracker <small>(August 2024 – February 2025)</small></h3> 134 - <ul> 135 - <li>- Designed and released a mobile app for gyms at Virginia Tech</li> 136 - <li>- Managed marketing and launch strategy</li> 137 - </ul> 138 - </section> 139 - 140 - <section> 141 - <h2>Awards</h2> 142 - <ul> 143 - <li>- Eagle Scout, Boy Scouts of America | July 2021</li> 144 - </ul> 145 - </section> 146 - </main> 147 - <script> 148 - // Mobile nav toggle functionality (brand/menu swap) 149 - document.addEventListener('DOMContentLoaded', function() { 150 - const navToggle = document.querySelector('.mobile-nav-toggle'); 151 - const brand = document.getElementById('brand'); 152 - const menu = document.getElementById('main-menu'); 153 - const headerControls = document.getElementById('header-controls'); 154 - function isMobile() { 155 - return window.innerWidth <= 600; 156 - } 157 - function showMenuInBar(show) { 158 - if (isMobile()) { 159 - if (show) { 160 - brand.style.display = 'none'; 161 - menu.style.display = 'flex'; 162 - menu.classList.add('menu-in-bar'); 163 - } else { 164 - brand.style.display = ''; 165 - menu.style.display = ''; 166 - menu.classList.remove('menu-in-bar'); 167 - } 168 - } else { 169 - brand.style.display = ''; 170 - menu.style.display = ''; 171 - menu.classList.remove('menu-in-bar'); 172 - } 173 - } 174 - if (navToggle && brand && menu) { 175 - navToggle.addEventListener('click', function() { 176 - const expanded = navToggle.getAttribute('aria-expanded') === 'true'; 177 - navToggle.setAttribute('aria-expanded', !expanded); 178 - showMenuInBar(!expanded); 179 - }); 180 - window.addEventListener('resize', function() { 181 - // Reset on resize 182 - if (!isMobile()) { 183 - showMenuInBar(false); 184 - navToggle.setAttribute('aria-expanded', false); 185 - } 186 - }); 187 - } 188 - }); 189 - </script> 190 - <script src="script.js"></script> 191 - </body> 192 - </html>
-376
script.js
··· 1 - // Accessibility menu logic 2 - (function() { 3 - const root = document.documentElement; 4 - const accessibilityBtn = document.getElementById('accessibility-btn'); 5 - const menu = document.getElementById('accessibility-menu'); 6 - let menuOpen = false; 7 - 8 - // Theme radio buttons 9 - const themeRadios = menu ? menu.querySelectorAll('input[name="theme-mode"]') : []; 10 - const themeRadioLabels = menu ? menu.querySelectorAll('.access-radio') : []; 11 - // Add system theme radio if not present 12 - if (menu && !menu.querySelector('input[value="system"]')) { 13 - const systemLabel = document.createElement('label'); 14 - systemLabel.className = 'access-radio'; 15 - const systemRadio = document.createElement('input'); 16 - systemRadio.type = 'radio'; 17 - systemRadio.name = 'theme-mode'; 18 - systemRadio.value = 'system'; 19 - systemLabel.appendChild(systemRadio); 20 - systemLabel.appendChild(document.createTextNode(' System')); 21 - // Insert as first option 22 - const section = menu.querySelector('.access-section'); 23 - if (section) section.insertBefore(systemLabel, section.children[1]); 24 - } 25 - // Re-query radios after possible insertion 26 - const allThemeRadios = menu ? menu.querySelectorAll('input[name="theme-mode"]') : []; 27 - 28 - // High contrast toggle 29 - const highContrastToggle = menu ? menu.querySelector('#high-contrast-toggle') : null; 30 - // Text size buttons 31 - const textIncreaseBtn = menu ? menu.querySelector('#text-increase') : null; 32 - const textDecreaseBtn = menu ? menu.querySelector('#text-decrease') : null; 33 - const textResetBtn = menu ? menu.querySelector('#text-reset') : null; 34 - 35 - function setTheme(mode) { 36 - root.classList.remove('dark-theme', 'light-theme'); 37 - if (mode === 'dark') { 38 - root.classList.add('dark-theme'); 39 - localStorage.setItem('theme', 'dark'); 40 - } else if (mode === 'light') { 41 - root.classList.add('light-theme'); 42 - localStorage.setItem('theme', 'light'); 43 - } else { 44 - // System: remove explicit theme, use OS preference 45 - localStorage.setItem('theme', 'system'); 46 - } 47 - // Update selected state for mobile button UI 48 - themeRadioLabels.forEach(label => { 49 - const input = label.querySelector('input[type="radio"]'); 50 - if (input) { 51 - if (input.value === mode) { 52 - label.classList.add('selected'); 53 - } else { 54 - label.classList.remove('selected'); 55 - } 56 - } 57 - }); 58 - } 59 - 60 - // Utility to announce status to screen readers 61 - function announceA11yStatus(message) { 62 - const status = document.getElementById('a11y-status'); 63 - if (status) { 64 - status.textContent = ''; 65 - setTimeout(() => { status.textContent = message; }, 10); 66 - } 67 - } 68 - 69 - function setHighContrast(enabled) { 70 - if (enabled) { 71 - root.classList.add('high-contrast'); 72 - root.classList.add('dark-theme'); // Always dark in high contrast 73 - // Disable theme radios 74 - allThemeRadios.forEach(radio => { 75 - radio.disabled = true; 76 - }); 77 - themeRadioLabels.forEach(label => { 78 - label.classList.add('disabled'); 79 - }); 80 - announceA11yStatus('High contrast mode enabled.'); 81 - } else { 82 - root.classList.remove('high-contrast'); 83 - // Enable theme radios 84 - allThemeRadios.forEach(radio => { 85 - radio.disabled = false; 86 - }); 87 - themeRadioLabels.forEach(label => { 88 - label.classList.remove('disabled'); 89 - }); 90 - // Restore selected theme 91 - const savedTheme = localStorage.getItem('theme') || 'light'; 92 - setTheme(savedTheme); 93 - // Set radio 94 - allThemeRadios.forEach(radio => { radio.checked = (radio.value === savedTheme); }); 95 - announceA11yStatus('High contrast mode disabled.'); 96 - } 97 - localStorage.setItem('highContrast', enabled ? '1' : '0'); 98 - } 99 - 100 - function setFontSize(size) { 101 - root.style.setProperty('--base-font-size', size + 'px'); 102 - localStorage.setItem('fontSize', size); 103 - } 104 - 105 - function getFontSize() { 106 - const val = parseInt(localStorage.getItem('fontSize'), 10); 107 - return isNaN(val) ? 16 : val; 108 - } 109 - 110 - function openMenu() { 111 - if (!menu) return; 112 - menu.style.display = 'flex'; 113 - accessibilityBtn.setAttribute('aria-expanded', 'true'); 114 - menuOpen = true; 115 - // Focus first input for accessibility 116 - setTimeout(() => { 117 - const firstInput = menu.querySelector('input, button'); 118 - if (firstInput) firstInput.focus(); 119 - }, 0); 120 - } 121 - function closeMenu() { 122 - if (!menu) return; 123 - menu.style.display = 'none'; 124 - accessibilityBtn.setAttribute('aria-expanded', 'false'); 125 - menuOpen = false; 126 - } 127 - function toggleMenu() { 128 - menuOpen ? closeMenu() : openMenu(); 129 - } 130 - 131 - // Event listeners 132 - if (accessibilityBtn) { 133 - accessibilityBtn.addEventListener('click', function(e) { 134 - e.stopPropagation(); 135 - toggleMenu(); 136 - }); 137 - accessibilityBtn.addEventListener('keydown', function(e) { 138 - if (e.key === 'Enter' || e.key === ' ') { 139 - e.preventDefault(); 140 - toggleMenu(); 141 - } 142 - }); 143 - } 144 - 145 - // Theme selection logic 146 - function isMobile() { 147 - return window.matchMedia && window.matchMedia('(max-width: 650px)').matches; 148 - } 149 - 150 - if (isMobile()) { 151 - // On mobile, treat .access-radio as buttons 152 - themeRadioLabels.forEach(label => { 153 - label.addEventListener('click', function(e) { 154 - e.preventDefault(); 155 - const input = label.querySelector('input[type="radio"]'); 156 - if (input && !input.disabled) { 157 - setTheme(input.value); 158 - } 159 - }); 160 - label.setAttribute('tabindex', '0'); 161 - label.addEventListener('keydown', function(e) { 162 - if (e.key === 'Enter' || e.key === ' ') { 163 - e.preventDefault(); 164 - const input = label.querySelector('input[type="radio"]'); 165 - if (input && !input.disabled) { 166 - setTheme(input.value); 167 - } 168 - } 169 - }); 170 - }); 171 - } else { 172 - // Desktop: radio logic 173 - allThemeRadios.forEach(radio => { 174 - radio.addEventListener('change', function() { 175 - if (this.checked) setTheme(this.value); 176 - }); 177 - }); 178 - } 179 - 180 - // High contrast toggle logic 181 - highContrastToggle && highContrastToggle.addEventListener('change', function() { 182 - setHighContrast(this.checked); 183 - }); 184 - 185 - // Text size logic 186 - textIncreaseBtn && textIncreaseBtn.addEventListener('click', function() { 187 - let size = getFontSize(); 188 - size = Math.min(size + 2, 28); 189 - setFontSize(size); 190 - }); 191 - textDecreaseBtn && textDecreaseBtn.addEventListener('click', function() { 192 - let size = getFontSize(); 193 - size = Math.max(size - 2, 12); 194 - setFontSize(size); 195 - }); 196 - textResetBtn && textResetBtn.addEventListener('click', function() { 197 - setFontSize(16); 198 - }); 199 - textResetBtn && textResetBtn.addEventListener('keydown', function(e) { 200 - if (e.key === 'Enter' || e.key === ' ') { 201 - e.preventDefault(); 202 - setFontSize(16); 203 - } 204 - }); 205 - 206 - // Close menu on outside click or Escape 207 - document.addEventListener('click', function(e) { 208 - if (menuOpen && menu && !menu.contains(e.target) && e.target !== accessibilityBtn) { 209 - closeMenu(); 210 - } 211 - }); 212 - document.addEventListener('keydown', function(e) { 213 - if (menuOpen && e.key === 'Escape') { 214 - closeMenu(); 215 - accessibilityBtn && accessibilityBtn.focus(); 216 - } 217 - // Keyboard navigation: arrow keys 218 - if (menuOpen && menu && (e.key === 'ArrowDown' || e.key === 'ArrowUp')) { 219 - const focusables = Array.from(menu.querySelectorAll('input, button, [role="button"], .access-radio')); 220 - const idx = focusables.indexOf(document.activeElement); 221 - let nextIdx = idx; 222 - if (e.key === 'ArrowDown') nextIdx = (idx + 1) % focusables.length; 223 - if (e.key === 'ArrowUp') nextIdx = (idx - 1 + focusables.length) % focusables.length; 224 - focusables[nextIdx].focus(); 225 - e.preventDefault(); 226 - } 227 - }); 228 - 229 - // On load: apply saved theme, high contrast, and font size 230 - window.addEventListener('DOMContentLoaded', function() { 231 - // Theme 232 - const savedTheme = localStorage.getItem('theme') || 'system'; 233 - setTheme(savedTheme); 234 - allThemeRadios.forEach(radio => { radio.checked = (radio.value === savedTheme); }); 235 - // High contrast 236 - const highContrast = localStorage.getItem('highContrast') === '1'; 237 - if (highContrast) setHighContrast(true); 238 - if (highContrastToggle) highContrastToggle.checked = highContrast; 239 - // Font size 240 - setFontSize(getFontSize()); 241 - }); 242 - })(); 243 - 244 - // Dynamically load header.html into #header-include 245 - function loadHeader() { 246 - const headerDiv = document.getElementById('header-include'); 247 - if (headerDiv) { 248 - fetch('header.html') 249 - .then(response => response.text()) 250 - .then(html => { 251 - headerDiv.insertAdjacentHTML('beforeend', html); 252 - // Set active tab in header navigation 253 - const navLinks = headerDiv.querySelectorAll('.menu a'); 254 - const page = window.location.pathname.split('/').pop() || 'index.html'; 255 - navLinks.forEach(link => { 256 - // Normalize both for comparison 257 - const linkHref = link.getAttribute('href'); 258 - if ( 259 - (page === '' && linkHref === 'index.html') || 260 - (page === linkHref) || 261 - (page === 'index.html' && linkHref === 'index.html') 262 - ) { 263 - link.classList.add('active'); 264 - } else { 265 - link.classList.remove('active'); 266 - } 267 - }); 268 - // Run scripts that depend on the loaded header 269 - initializeAccessibility(); 270 - initializeMobileNav(); 271 - }); 272 - } 273 - } 274 - document.addEventListener('DOMContentLoaded', loadHeader); 275 - 276 - // Mobile navigation toggle 277 - function initializeMobileNav() { 278 - const toggleBtn = document.getElementById('mobile-nav-toggle'); 279 - const navContent = document.getElementById('header-controls'); 280 - 281 - if (toggleBtn && navContent) { 282 - toggleBtn.addEventListener('click', () => { 283 - const isExpanded = toggleBtn.getAttribute('aria-expanded') === 'true'; 284 - toggleBtn.setAttribute('aria-expanded', !isExpanded); 285 - navContent.classList.toggle('mobile-nav-open'); 286 - }); 287 - } 288 - } 289 - 290 - // VT Gym Tracker Carousel Logic 291 - (function() { 292 - const carousel = document.getElementById('app-screenshots'); 293 - if (!carousel) return; 294 - const items = carousel.querySelectorAll('.screenshot-item'); 295 - const prevBtn = document.getElementById('carousel-prev'); 296 - const nextBtn = document.getElementById('carousel-next'); 297 - const dotsContainer = document.getElementById('carousel-dots'); 298 - let current = 0; 299 - let touchStartX = null; 300 - 301 - function showSlide(idx) { 302 - items.forEach((item, i) => { 303 - item.style.display = (i === idx) ? 'block' : 'none'; 304 - item.setAttribute('aria-hidden', i === idx ? 'false' : 'true'); 305 - }); 306 - // Update dots 307 - if (dotsContainer) { 308 - Array.from(dotsContainer.children).forEach((dot, i) => { 309 - dot.classList.toggle('active', i === idx); 310 - dot.setAttribute('aria-selected', i === idx ? 'true' : 'false'); 311 - dot.setAttribute('tabindex', i === idx ? '0' : '-1'); 312 - }); 313 - } 314 - current = idx; 315 - } 316 - 317 - function goToSlide(idx) { 318 - if (idx < 0) idx = items.length - 1; 319 - if (idx >= items.length) idx = 0; 320 - showSlide(idx); 321 - } 322 - 323 - // Dots 324 - if (dotsContainer) { 325 - dotsContainer.innerHTML = ''; 326 - items.forEach((_, i) => { 327 - const dot = document.createElement('button'); 328 - dot.className = 'carousel-dot'; 329 - dot.setAttribute('role', 'tab'); 330 - dot.setAttribute('aria-label', `Go to screenshot ${i+1}`); 331 - dot.setAttribute('tabindex', i === 0 ? '0' : '-1'); 332 - dot.setAttribute('aria-selected', i === 0 ? 'true' : 'false'); 333 - dot.addEventListener('click', () => goToSlide(i)); 334 - dot.addEventListener('keydown', (e) => { 335 - if (e.key === 'Enter' || e.key === ' ') { 336 - e.preventDefault(); 337 - goToSlide(i); 338 - } 339 - }); 340 - dotsContainer.appendChild(dot); 341 - }); 342 - } 343 - 344 - // Button events 345 - prevBtn && prevBtn.addEventListener('click', () => goToSlide(current - 1)); 346 - nextBtn && nextBtn.addEventListener('click', () => goToSlide(current + 1)); 347 - 348 - // Keyboard navigation 349 - carousel.addEventListener('keydown', (e) => { 350 - if (e.key === 'ArrowLeft') { 351 - goToSlide(current - 1); 352 - } else if (e.key === 'ArrowRight') { 353 - goToSlide(current + 1); 354 - } 355 - }); 356 - 357 - // Touch swipe support 358 - carousel.addEventListener('touchstart', (e) => { 359 - if (e.touches.length === 1) { 360 - touchStartX = e.touches[0].clientX; 361 - } 362 - }); 363 - carousel.addEventListener('touchend', (e) => { 364 - if (touchStartX !== null && e.changedTouches.length === 1) { 365 - const dx = e.changedTouches[0].clientX - touchStartX; 366 - if (Math.abs(dx) > 40) { 367 - if (dx > 0) goToSlide(current - 1); 368 - else goToSlide(current + 1); 369 - } 370 - touchStartX = null; 371 - } 372 - }); 373 - 374 - // Initialize 375 - showSlide(0); 376 - })();
+188 -2536
style.css
··· 1 - /* Directional View Transition setup */ 2 - :root { 3 - /* Color theme variables */ 4 - --bg-color: #ffffff; 5 - --text-color: #333333; 6 - --link-color: #444444; 7 - --link-hover-color: #222222; 8 - --input-bg: #ffffff; 9 - --input-text: #000000; 10 - --input-border: #cccccc; 11 - --nav-bg: rgba(255,255,255,0.97); 12 - --nav-active-bg: #f0f1f3; 13 - --nav-shadow: 0 2px 8px rgba(0,0,0,0.06); 14 - --nav-border: 1.5px solid #d0d7de; 15 - --btn-bg: #f4f4f7; 16 - --btn-bg-hover: #e0e0e7; 17 - --btn-text: #232b36; 18 - --btn-active-bg: #111; 19 - --btn-active-text: #fff; 20 - --btn-active-underline: #232b36; 21 - /* VT Brand Colors */ 22 - --vt-maroon: #861F41; 23 - --vt-burntOrange: #E5751F; 24 - --vt-hokieStone: #75787b; 25 - --vt-white: #FFFFFF; 26 - --vt-purple: #642667; 27 - --vt-pink: #CE0058; 28 - --vt-yellow: #F7EA48; 29 - --vt-teal: #508590; 30 - --vt-turquoise: #2CD5C4; 31 - --vt-grey: #D7D2CB; 32 - --vt-smoke: #E5E1E6; 33 - --vt-impactOrange: #CA4F00; 34 - } 35 - 36 - /* Dark theme overrides */ 37 - .dark-theme { 38 - --bg-color: #1a1a1a; 39 - --text-color: #e0e0e0; 40 - --link-color: #bbbbbb; 41 - --link-hover-color: #ffffff; 42 - --input-bg: #333333; 43 - --input-text: #f0f0f0; 44 - --input-border: #555555; 45 - --nav-bg: rgba(30,30,30,0.98); 46 - --nav-active-bg: #232b36; 47 - --nav-shadow: 0 4px 24px rgba(0,0,0,0.32); 48 - --nav-border: 1.5px solid #333a40; 49 - --btn-bg: #232b36; 50 - --btn-bg-hover: #232b36; 51 - --btn-text: #fff; 52 - --btn-active-bg: #fff; 53 - --btn-active-text: #232b36; 54 - --btn-active-underline: #fff; 55 - } 56 - 57 - /* System mode: use the same variables as .dark-theme and :root via media queries */ 58 - @media (prefers-color-scheme: dark) { 59 - :root:not(.light-theme):not(.dark-theme) { 60 - --bg-color: #1a1a1a; 61 - --text-color: #e0e0e0; 62 - --link-color: #bbbbbb; 63 - --link-hover-color: #ffffff; 64 - --input-bg: #333333; 65 - --input-text: #f0f0f0; 66 - --input-border: #555555; 67 - --nav-bg: rgba(30,30,30,0.98); 68 - --nav-active-bg: #232b36; 69 - --nav-shadow: 0 4px 24px rgba(0,0,0,0.32); 70 - --nav-border: 1.5px solid #333a40; 71 - --btn-bg: #232b36; 72 - --btn-bg-hover: #232b36; 73 - --btn-text: #fff; 74 - --btn-active-bg: #fff; 75 - --btn-active-text: #232b36; 76 - --btn-active-underline: #fff; 77 - } 78 - } 79 - @media (prefers-color-scheme: light) { 80 - :root:not(.light-theme):not(.dark-theme) { 81 - --bg-color: #ffffff; 82 - --text-color: #333333; 83 - --link-color: #444444; 84 - --link-hover-color: #222222; 85 - --input-bg: #ffffff; 86 - --input-text: #000000; 87 - --input-border: #cccccc; 88 - --nav-bg: rgba(255,255,255,0.97); 89 - --nav-active-bg: #f0f1f3; 90 - --nav-shadow: 0 2px 8px rgba(0,0,0,0.06); 91 - --nav-border: 1.5px solid #d0d7de; 92 - --btn-bg: #f4f4f7; 93 - --btn-bg-hover: #e0e0e7; 94 - --btn-text: #232b36; 95 - --btn-active-bg: #111; 96 - --btn-active-text: #fff; 97 - --btn-active-underline: #232b36; 98 - } 99 - } 100 - 101 - /* Global resets/base styles */ 102 - * { 1 + /* Reset and Base Styles - Matching wongmjane.com exactly */ 2 + *, 3 + *::before, 4 + *::after { 103 5 box-sizing: border-box; 104 - } 105 - 106 - /* Name and social links container */ 107 - .name-and-social { 108 - display: flex; 109 - align-items: center; 110 - gap: 1rem; 111 - margin: 1rem 0; 112 - } 113 - 114 - /* Social links styling */ 115 - .social-links { 116 - display: flex; 117 - gap: 1rem; 118 - align-items: center; 119 - } 120 - 121 - .social-links a { 122 - display: flex; 123 - align-items: center; 124 - justify-content: center; 125 - width: 2.5rem; 126 - height: 2.5rem; 127 - border-radius: 50%; 128 - background: transparent; 129 - color: var(--text-color); 130 - text-decoration: none; 131 - transition: all 0.2s ease; 132 - border: none; 133 - } 134 - 135 - .social-links a:hover, 136 - .social-links a:focus { 137 - background: transparent; 138 - color: var(--link-hover-color); 139 - transform: translateY(-2px); 140 - } 141 - 142 - .social-links i { 143 - font-size: 1.2rem; 144 - } 145 - 146 - .social-links .bluesky-icon, 147 - .social-links .github-icon, 148 - .social-links .linkedin-icon { 149 - width: 1.2rem; 150 - height: 1.2rem; 151 - fill: currentColor; 152 - } 153 - 154 - .dark-theme .social-links a { 155 - background: transparent; 156 - color: var(--text-color); 157 - border: none; 158 - } 159 - 160 - .dark-theme .social-links a:hover, 161 - .dark-theme .social-links a:focus { 162 - background: transparent; 163 - color: var(--link-hover-color); 164 - } 165 - html, body { 6 + border: 0 solid; 166 7 margin: 0; 167 8 padding: 0; 168 - background: var(--bg-color); 169 - color: var(--text-color); 170 - font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif; 171 - font-size: 16px; 172 - line-height: 1.6; 173 9 } 174 10 175 - /* Layout containers */ 176 - .container { 177 - max-width: 800px; 178 - margin: 0 auto; 179 - padding: 1rem; 11 + html { 12 + -webkit-text-size-adjust: 100%; 13 + tab-size: 4; 14 + -webkit-tap-highlight-color: transparent; 15 + line-height: 1.5; 180 16 } 181 17 182 - /* Add a new class for the right-side controls */ 183 - .header-controls { 184 - display: flex; 185 - align-items: center; 186 - gap: 0.5rem; 18 + img, svg, video { 19 + vertical-align: middle; 20 + display: block; 187 21 } 188 22 189 - /* Add a divider for the right-side controls */ 190 - .header-divider { 191 - width: 0; 192 - height: 2.2rem; 193 - border-left: var(--nav-border); 194 - margin: 0 0.3rem 0 1.1rem; 195 - align-self: center; 196 - border-radius: 2px; 197 - background: none; 198 - transition: border-color 0.2s; 199 - } 200 - .dark-theme .header-divider { 201 - border-left: var(--nav-border); 202 - } 203 - .high-contrast .header-divider { 204 - border-left: 2px solid #ffff00 !important; 205 - background: none !important; 23 + img, video { 24 + max-width: 100%; 25 + height: auto; 206 26 } 207 27 208 - /* Accessibility icon (Aa) styling, no button look */ 209 - .accessibility-icon { 210 - display: flex; 211 - align-items: center; 212 - justify-content: center; 213 - width: 2.8rem; 214 - height: 2.8rem; 215 - font-size: 2rem; 216 - color: var(--text-color); 217 - background: none; 218 - border: none; 219 - border-radius: 50%; 220 - cursor: pointer; 221 - transition: color 0.15s; 222 - outline: none; 223 - margin-left: 0; 224 - } 225 - .accessibility-icon .material-symbols-outlined { 226 - font-size: 2rem; 227 - line-height: 1; 228 - display: flex; 229 - align-items: center; 230 - justify-content: center; 231 - cursor: pointer; 232 - } 233 - .accessibility-icon:focus, .accessibility-icon:hover { 234 - background: none; 235 - color: var(--link-hover-color); 236 - outline: none; 237 - box-shadow: none; 238 - } 239 - .dark-theme .accessibility-icon:focus, .dark-theme .accessibility-icon:hover { 240 - background: none; 241 - color: #fff; 242 - outline: none; 243 - box-shadow: none; 244 - } 245 - 246 - /* Remove button-specific styles from accessibility icon */ 247 - #accessibility-btn { 248 - all: unset; 28 + a { 29 + color: inherit; 30 + text-decoration: inherit; 249 31 } 250 32 251 - /* Header navigation */ 252 - header { 253 - margin-top: 1rem; 254 - } 255 - header nav { 256 - display: flex; 257 - align-items: center; 258 - justify-content: space-between; 259 - background: var(--nav-bg); 260 - border-radius: 1.5rem; 261 - box-shadow: var(--nav-shadow); 262 - border: var(--nav-border); /* Add border */ 263 - padding: 0.5rem 2.2rem 0.5rem 1.5rem; 264 - margin-top: 0.2rem; 265 - gap: 1.2rem; 266 - height: 3.6rem; 267 - } 268 - .brand { 269 - font-weight: bold; 270 - font-size: 1.2em; 271 - text-decoration: none; 272 - color: var(--text-color); 273 - margin-right: 1.2rem; 274 - letter-spacing: 0.5px; 275 - display: flex; 276 - align-items: center; 277 - height: 100%; 278 - white-space: nowrap; 279 - } 280 - .menu { 33 + ul, ol { 281 34 list-style: none; 282 - margin: 0; 283 - padding: 0; 284 - display: flex; 285 - gap: 1.2rem; 286 - justify-content: flex-end; 287 - align-items: center; 288 - height: 100%; 289 - } 290 - .menu a { 291 - display: flex; 292 - align-items: center; 293 - background: none; 294 - color: var(--link-color); 295 - font-weight: 600; /* Unified font-weight */ 296 - font-size: 1.05em; 297 - padding: 0.2em 0.7em 0.2em 0.7em; 298 - border: none; 299 - border-radius: 0; 300 - box-shadow: none; 301 - text-decoration: none; 302 - transition: color 0.15s, opacity 0.15s; 303 - position: relative; 304 - height: 100%; 305 - margin-top: 10px; 306 - opacity: 0.55; /* Lower opacity for non-active tabs */ 307 - } 308 - .menu a:hover, .menu a:focus { 309 - color: var(--link-hover-color); 310 - background: none; 311 - outline: none; 312 - opacity: 0.85; /* Slightly higher on hover */ 313 - } 314 - .menu a.active { 315 - color: #111 !important; /* Pure black for active tab in light theme */ 316 - font-weight: 600; /* Unified font-weight */ 317 - background: none; 318 - box-shadow: none; 319 - border-radius: 0; 320 - z-index: 1; 321 - opacity: 1; 322 - } 323 - .dark-theme .menu a.active { 324 - color: #fff !important; /* Pure white for active tab in dark theme */ 325 - } 326 - /* System mode: active tab color matches system theme */ 327 - @media (prefers-color-scheme: dark) { 328 - :root:not(.light-theme):not(.dark-theme) .menu a.active { 329 - color: #fff !important; 330 - } 331 - } 332 - @media (prefers-color-scheme: light) { 333 - :root:not(.light-theme):not(.dark-theme) .menu a.active { 334 - color: #111 !important; 335 - } 336 - } 337 - #theme-toggle { 338 - margin-left: 1.2rem; 339 - display: flex; 340 - align-items: center; 341 - justify-content: center; 342 - width: 2.4rem; 343 - height: 2.4rem; 344 - border: none; 345 - background: none; 346 - color: var(--text-color); 347 - border-radius: 50%; 348 - cursor: pointer; 349 - transition: background 0.15s, color 0.15s, box-shadow 0.15s; 350 - box-shadow: 0 1px 2px rgba(0,0,0,0.04); /* Softer, subtler shadow */ 351 - font-size: 1.2rem; 352 - position: relative; 353 - } 354 - #theme-toggle:hover, #theme-toggle:focus { 355 - background: var(--link-hover-color); 356 - color: #fff; 357 - outline: none; 358 - } 359 - /* Make sun icon black on hover in dark mode */ 360 - .dark-theme #theme-toggle:hover .icon-sun svg, 361 - .dark-theme #theme-toggle:focus .icon-sun svg { 362 - color: #111; 363 - } 364 - #theme-toggle svg { 365 - display: block; 366 - } 367 - .icon-sun, .icon-moon { 368 - position: absolute; 369 - left: 50%; 370 - top: 50%; 371 - transform: translate(-50%, -50%); 372 35 } 373 36 374 - /* Mobile Nav Toggle */ 375 - .mobile-nav-toggle { 376 - display: none; /* Hidden on desktop */ 377 - background: none; 378 - border: none; 379 - cursor: pointer; 380 - padding: 0.5rem; 381 - z-index: 1002; /* Ensure above nav */ 382 - } 383 - 384 - .hamburger-icon { 385 - display: block; 386 - width: 24px; 387 - height: 2px; 388 - background-color: var(--text-color); 389 - position: relative; 390 - transition: background-color 0.2s ease-in-out; 391 - } 392 - 393 - .hamburger-icon::before, 394 - .hamburger-icon::after { 395 - content: ''; 396 - position: absolute; 397 - left: 0; 398 - width: 100%; 399 - height: 2px; 400 - background-color: var(--text-color); 401 - transition: transform 0.2s ease-in-out, top 0.2s ease-in-out; 402 - } 403 - 404 - .hamburger-icon::before { 405 - top: -8px; 406 - } 407 - 408 - .hamburger-icon::after { 409 - top: 8px; 410 - } 411 - 412 - /* "X" icon when nav is open */ 413 - .mobile-nav-toggle[aria-expanded="true"] .hamburger-icon { 414 - background-color: transparent; /* Middle bar disappears */ 415 - } 416 - 417 - .mobile-nav-toggle[aria-expanded="true"] .hamburger-icon::before { 418 - transform: rotate(45deg); 419 - top: 0; 420 - } 421 - 422 - .mobile-nav-toggle[aria-expanded="true"] .hamburger-icon::after { 423 - transform: rotate(-45deg); 424 - top: 0; 37 + /* CSS Custom Properties - Matching wongmjane.com */ 38 + :root { 39 + --font-sans: "Schibsted Grotesk", ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; 40 + 41 + /* Light mode colors */ 42 + --color-bg: oklch(100% 0.003 250); 43 + --color-bg-secondary: oklch(99% 0.003 250); 44 + --color-bg-tertiary: oklch(97% 0.005 250); 45 + --color-border: oklch(93% 0.007 250); 46 + --color-text: oklch(30% 0.028 250); 47 + --color-text-muted: oklch(50% 0.022 250); 48 + --color-accent: oklch(60% 0.26 235); 49 + --color-accent-hover: oklch(74% 0.25 235); 425 50 } 426 51 427 - /* Responsive adjustments */ 428 - @media (max-width: 650px) { 429 - header nav { 430 - flex-direction: row; 431 - flex-wrap: nowrap; /* Changed from wrap */ 432 - align-items: center; 433 - justify-content: space-between; 434 - height: 3.6rem; /* Set fixed height */ 435 - padding: 0.5rem 1rem; 436 - gap: 0.5rem; 437 - margin-top: 0.7rem; 438 - position: relative; /* For menu positioning */ 439 - } 440 - .brand { 441 - margin-right: 0; 442 - margin-bottom: 0; /* Removed bottom margin */ 443 - justify-content: flex-start; 444 - } 445 - .header-controls { 446 - display: flex !important; 447 - position: static !important; 448 - flex-direction: row; 449 - align-items: center; 450 - gap: 0.5rem; 451 - background: none; 452 - box-shadow: none; 453 - border: none; 454 - padding: 0; 455 - } 456 - .header-controls.mobile-nav-open { 457 - display: flex; 458 - } 459 - .menu { 460 - display: none; 461 - flex-direction: column; 462 - gap: 0.3rem; 463 - align-items: stretch; 464 - justify-content: flex-start; 465 - } 466 - .menu a { 467 - font-size: 1em; 468 - padding: 0.3em 0.5em; 469 - margin-top: 0; 470 - justify-content: flex-start; 471 - } 472 - #theme-toggle { 473 - margin-left: 0; 474 - align-self: flex-end; 475 - width: 2rem; 476 - height: 2rem; 477 - font-size: 1rem; 478 - } 479 - .mobile-nav-toggle { 480 - display: block; 481 - } 482 - .header-divider { 483 - display: none !important; 52 + @media (prefers-color-scheme: dark) { 53 + :root { 54 + --color-bg: oklch(10% 0.034 250); 55 + --color-bg-secondary: oklch(20% 0.031 250); 56 + --color-bg-tertiary: oklch(30% 0.028 250); 57 + --color-border: oklch(40% 0.025 250); 58 + --color-text: oklch(97% 0.005 250); 59 + --color-text-muted: oklch(87% 0.01 250); 60 + --color-accent: oklch(74% 0.25 235); 61 + --color-accent-hover: oklch(81% 0.2 235); 484 62 } 485 63 } 486 64 487 - @media (min-width: 601px) { 488 - .header-controls { 489 - display: flex !important; 490 - position: static; 491 - max-height: none; 492 - opacity: 1; 493 - flex-direction: row; 494 - align-items: center; 495 - gap: 1.2rem; 496 - background: none; 497 - box-shadow: none; 498 - border: none; 499 - padding: 0; 500 - } 501 - .header-controls { 502 - padding-right: 1.2rem; 503 - } 504 - .brand { 505 - padding-left: 1.2rem; 506 - } 507 - .menu { 508 - display: flex; 509 - flex-direction: row; 510 - gap: 1.2rem; 511 - align-items: center; 512 - width: auto; 513 - background: none; 514 - padding: 0; 515 - margin: 0; 516 - border: none; 517 - box-shadow: none; 518 - } 519 - .menu li { 520 - flex: none; 521 - text-align: left; 522 - list-style: none; 523 - margin: 0; 524 - padding: 0; 525 - } 526 - .menu a { 527 - display: inline-block; 528 - width: auto; 529 - padding: 0.3em 0.8em; 530 - font-size: 1em; 531 - border-radius: 0.7em; 532 - background: none; 533 - border: none; 534 - margin: 0; 535 - text-align: center; 536 - transition: background 0.15s, color 0.15s; 537 - } 538 - .mobile-nav-toggle { 539 - display: none; 65 + /* Font smoothing */ 66 + @media screen { 67 + html { 68 + -moz-osx-font-smoothing: grayscale; 69 + -webkit-font-smoothing: antialiased; 540 70 } 541 71 } 542 72 543 - /* Intro (About section) */ 544 - .intro { 545 - display: flex; 546 - align-items: flex-start; 547 - gap: 2rem; 548 - margin: 2rem 0; 549 - } 550 - .headshot { 551 - width: 150px; 552 - height: 150px; 553 - object-fit: cover; 554 - border-radius: 50%; 555 - } 556 - .intro-text h1 { 557 - margin: 0 0 0.3rem; 558 - } 559 - .tagline { 560 - font-style: italic; 561 - opacity: 0.8; 562 - margin: 0 0 1rem; 563 - } 564 - .tagline .sep { 565 - opacity: 0.5; 566 - margin: 0 0.4em; 567 - } 568 - 569 - /* Typography & element spacing */ 570 - h1 { font-size: 2em; margin: 1rem 0; } 571 - h2 { font-size: 1.5em; margin: 1.5rem 0 0.75rem; } 572 - h3 { font-size: 1.2em; margin: 1rem 0 0.5rem; } 573 - small { opacity: 0.7; } 574 - p { margin: 0.5rem 0 1rem; } 575 - ul { 576 - padding-left: 1.2rem; 577 - margin: 0.5rem 0 1rem; 578 - } 579 - ul li { margin-bottom: 0.5rem; } 580 - 581 - /* Remove bullet points from resume lists */ 582 - .resume-main ul { 583 - list-style: none; 584 - padding-left: 0; 585 - } 586 - 587 - /* Simple Resume Styles */ 588 - .resume-main { 589 - max-width: 800px; 590 - margin: 0 auto; 591 - line-height: 1.6; 592 - } 593 - 594 - .contact-info { 595 - text-align: center; 596 - margin-bottom: 2rem; 597 - } 598 - 599 - .contact-info h2 { 600 - margin: 0 0 0.5rem 0; 601 - } 602 - 603 - .contact-info p { 73 + /* Body */ 74 + body { 75 + background-color: var(--color-bg); 76 + color: var(--color-text); 77 + font-family: var(--font-sans); 78 + font-feature-settings: "kern" on, "liga" on, "dlig" on, "case" on; 79 + font-style: normal; 80 + font-synthesis: none; 81 + min-height: 100%; 604 82 margin: 0; 605 - opacity: 0.8; 606 - } 607 - 608 - .resume-main section { 609 - margin-bottom: 2rem; 610 - } 611 - 612 - .resume-main h2 { 613 - margin: 0 0 1rem 0; 614 - } 615 - 616 - .resume-main h3 { 617 - margin: 1.5rem 0 0.5rem 0; 618 - } 619 - 620 - .resume-main h3:first-of-type { 621 - margin-top: 0; 622 - } 623 - 624 - .resume-main ul { 625 - margin: 0.5rem 0 1rem 0; 626 - } 627 - 628 - .resume-main li { 629 - margin-bottom: 0.3rem; 630 - } 631 - 632 - /* General link styles */ 633 - a { 634 - color: var(--text-color); 635 - text-decoration: underline; 636 - transition: color 0.15s; 637 - } 638 - 639 - a:hover, a:focus { 640 - color: var(--text-color); 641 - text-decoration: underline; 642 - } 643 - 644 - /* Buttons */ 645 - .btn { 646 - display: inline-block; 647 - background: var(--btn-bg); 648 - color: var(--btn-text); 649 - text-decoration: none; 650 - padding: 0.35em 1em; 651 - border: 1px solid #333; 652 - border-radius: 8px; 653 - font-weight: 600; 654 - font-size: 0.98em; 655 - font-family: inherit; 656 - cursor: pointer; 657 - box-shadow: 0 1.5px 6px rgba(0,0,0,0.07); /* Softer, more natural shadow */ 658 - transition: background 0.15s, color 0.15s, box-shadow 0.15s, border 0.15s; 659 - } 660 - .btn:hover, .btn:focus { 661 - background: var(--btn-bg-hover); 662 - color: var(--btn-text); 663 - border-color: #444; 664 - outline: none; 665 - box-shadow: 0 3px 12px rgba(0,0,0,0.10); /* Softer hover shadow */ 666 - } 667 - .btn:active { 668 - background: var(--btn-active-bg); 669 - color: var(--btn-active-text); 670 - border-color: #222; 83 + padding: 0; 84 + -webkit-tap-highlight-color: transparent; 85 + display: contents; 671 86 } 672 87 673 - /* Form styles */ 674 - form p { margin: 0 0 1rem; } 675 - label { font-weight: 500; } 676 - input[type=text], input[type=email], textarea { 677 - width: 100%; 678 - padding: 0.5rem; 679 - background: var(--input-bg); 680 - color: var(--input-text); 681 - border: 1px solid var(--input-border); 682 - border-radius: 4px; 683 - font: inherit; 684 - } 685 - textarea { resize: vertical; } 686 - 687 - /* Enhanced mobile responsiveness */ 688 - @media (max-width: 650px) { 689 - html, body { 690 - font-size: 15px; 691 - padding: 0; 692 - } 693 - .container { 694 - padding: 0.5rem; 695 - max-width: 100%; 696 - } 697 - .intro { 698 - flex-direction: column; 699 - gap: 1rem; 700 - margin: 1rem 0; 701 - align-items: center; 702 - } 703 - .headshot { 704 - width: 100px; 705 - height: 100px; 706 - } 707 - .intro-text h1 { 708 - font-size: 1.3em; 709 - } 710 - h1 { 711 - font-size: 1.4em; 712 - } 713 - h2 { 714 - font-size: 1.1em; 715 - } 716 - h3 { 717 - font-size: 1em; 718 - } 719 - .btn { 720 - font-size: 0.95em; 721 - padding: 0.3em 0.7em; 722 - } 723 - form p { 724 - margin-bottom: 0.7rem; 725 - } 726 - input[type=text], input[type=email], textarea { 727 - font-size: 1em; 728 - padding: 0.4rem; 729 - } 730 - ul { 731 - padding-left: 1rem; 732 - } 733 - /* Make images and containers fluid */ 734 - img, .headshot { 735 - max-width: 100%; 736 - height: auto; 737 - } 738 - 739 - /* Name and social links mobile styling */ 740 - .name-and-social { 741 - flex-direction: column; 742 - gap: 0.75rem; 743 - align-items: flex-start; 744 - } 745 - 746 - /* Social links mobile styling */ 747 - .social-links { 748 - gap: 0.75rem; 749 - justify-content: flex-start; 750 - } 751 - 752 - .social-links a { 753 - width: 2.2rem; 754 - height: 2.2rem; 755 - } 756 - 757 - .social-links i { 758 - font-size: 1rem; 759 - } 760 - 761 - /* Resume header mobile styling - keep button on same line */ 762 - .resume-header { 763 - flex-direction: row; 764 - align-items: center; 765 - justify-content: space-between; 766 - gap: 0.75rem; 767 - } 768 - 769 - .resume-header h1 { 770 - margin: 0; 771 - flex-shrink: 0; 772 - } 773 - 774 - .pdf-btn { 775 - font-size: 0.9em; 776 - padding: 0.4em 1.2em; 777 - flex-shrink: 0; 778 - } 779 - } 780 - 781 - .resume-header { 88 + /* Main */ 89 + main { 782 90 display: flex; 91 + flex-grow: 1; 92 + background-color: var(--color-bg); 93 + min-height: 100dvh; 94 + justify-content: center; 783 95 align-items: center; 784 - justify-content: space-between; 785 - gap: 1rem; 786 96 } 787 97 788 - .resume-header h1 { 789 - margin-top: 0; 790 - } 791 98 792 - .pdf-btn { 793 - background: var(--nav-bg); 794 - color: var(--text-color); 795 - border: var(--nav-border); 796 - border-radius: 1.5rem; 797 - box-shadow: var(--nav-shadow); 798 - padding: 0.5em 1.5em; 799 - font-weight: 600; 800 - font-size: 1em; 801 - transition: background 0.15s, color 0.15s, box-shadow 0.15s, border 0.15s; 802 - text-decoration: none; 803 - display: inline-block; 804 - } 805 - .pdf-btn:hover, .pdf-btn:focus { 806 - background: var(--nav-active-bg); 807 - color: var(--link-hover-color); 808 - box-shadow: 0 4px 16px rgba(0,0,0,0.10); 809 - outline: none; 810 - } 811 - 812 - .projects-main > h1 { 813 - margin-top: 0; 814 - } 815 - 816 - /* Accessibility: High Contrast Mode */ 817 - .high-contrast { 818 - --bg-color: #000 !important; 819 - --text-color: #fff !important; 820 - --link-color: #ffff00 !important; 821 - --link-hover-color: #00ffff !important; 822 - --input-bg: #000 !important; 823 - --input-text: #fff !important; 824 - --input-border: #fff !important; 825 - --nav-bg: #000 !important; 826 - --nav-active-bg: #222 !important; 827 - --nav-shadow: none !important; 828 - --nav-border: 2px solid #fff !important; 829 - --btn-bg: #000 !important; 830 - --btn-bg-hover: #222 !important; 831 - --btn-text: #fff !important; 832 - --btn-active-bg: #fff !important; 833 - --btn-active-text: #000 !important; 834 - --btn-active-underline: #fff !important; 835 - } 836 - 837 - /* Accessibility: Font size scaling */ 838 - :root { 839 - --base-font-size: 16px; 840 - } 841 - html, body { 842 - font-size: var(--base-font-size); 843 - transition: background 0.2s, color 0.2s, font-size 0.2s; 844 - } 845 - 846 - /* Accessibility Button (matches theme toggle style) */ 847 - /* 848 - #accessibility-btn { 849 - margin-left: 1.2rem; 99 + /* Content wrapper */ 100 + .content-wrapper { 850 101 display: flex; 102 + flex-direction: column; 851 103 align-items: center; 852 104 justify-content: center; 853 - width: 2.4rem; 854 - height: 2.4rem; 855 - border: 1.5px solid #c0c0c0; 856 - background: #f7f7f9; 857 - color: var(--text-color); 858 - border-radius: 50%; 859 - cursor: pointer; 860 - transition: background 0.15s, color 0.15s, border 0.15s; 861 - font-size: 1.2rem; 862 - position: relative; 863 - } 864 - #accessibility-btn:hover, #accessibility-btn:focus { 865 - background: #ececf0; 866 - color: #111; 867 - outline: none; 868 - border-color: #888; 869 - } 870 - .dark-theme #accessibility-btn { 871 - border: 1.5px solid #444a55; 872 - background: #23242a; 873 - color: #fff; 874 - } 875 - .dark-theme #accessibility-btn:hover, .dark-theme #accessibility-btn:focus { 876 - background: #2d2e36; 877 - color: #fff; 878 - border-color: #888; 879 - } 880 - */ 881 - .icon-accessibility svg { 882 - display: block; 883 - } 884 - .icon-accessibility { 885 - font-size: 1em; 886 - font-weight: bold; 887 - font-family: inherit; 888 - letter-spacing: 0; 889 - display: flex; 890 - align-items: center; 891 - justify-content: center; 892 - height: 100%; 105 + padding: 2rem 1rem; 893 106 width: 100%; 894 107 } 895 108 896 - /* Accessibility Menu */ 897 - .accessibility-menu { 898 - position: absolute; 899 - right: 0; 900 - top: 3.2rem; 901 - background: var(--nav-bg); 902 - border: var(--nav-border); 903 - box-shadow: var(--nav-shadow); 904 - border-radius: 1.2rem; 905 - padding: 0.7rem 1.1rem; 906 - z-index: 1000; 907 - min-width: 210px; 109 + /* Profile container */ 110 + .profile-container { 908 111 display: flex; 909 112 flex-direction: column; 910 - gap: 0.7rem; 911 - font-size: 1em; 912 - } 913 - .access-section { 914 - display: flex; 915 - flex-direction: column; 916 - gap: 0.3rem; 917 - margin-bottom: 0.2rem; 918 - } 919 - .access-label { 920 - font-weight: 600; 921 - font-size: 1em; 922 - margin-bottom: 0.1em; 923 - color: var(--text-color); 924 - opacity: 0.8; 925 - } 926 - .access-radio { 927 - display: flex; 928 - align-items: center; 929 - gap: 0.5em; 930 - font-size: 1em; 931 - cursor: pointer; 932 - margin-bottom: 0.1em; 933 - } 934 - .access-radio input[type="radio"] { 935 - accent-color: var(--link-color); 936 - margin-right: 0.4em; 937 - } 938 - .access-toggle { 939 - display: flex; 940 - align-items: center; 941 - gap: 0.5em; 942 - font-size: 1em; 943 - cursor: pointer; 944 - } 945 - .access-toggle input[type="checkbox"] { 946 - accent-color: var(--link-color); 947 - margin-right: 0.4em; 948 - } 949 - .access-textsize { 950 - flex-direction: row; 951 113 align-items: center; 952 114 justify-content: center; 953 - gap: 0.5em; 954 - } 955 - .access-textsize .access-label { 956 - margin-right: 0.7em; 957 - margin-bottom: 0; 958 - } 959 - .access-textsize button { 960 - background: var(--btn-bg); 961 - color: var(--btn-text); 962 - border: 1px solid #333; 963 - border-radius: 6px; 964 - font-weight: 600; 965 - font-size: 1em; 966 - font-family: inherit; 967 - cursor: pointer; 968 - padding: 0.2em 0.7em; 969 - margin: 0 0.1em; 970 - transition: background 0.15s, color 0.15s, border 0.15s; 971 - } 972 - .access-textsize button:hover, .access-textsize button:focus { 973 - background: var(--btn-bg-hover); 974 - color: var(--btn-text); 975 - border-color: #444; 976 - outline: none; 977 - } 978 - .access-textsize button:active { 979 - background: var(--btn-active-bg); 980 - color: var(--btn-active-text); 981 - border-color: #222; 982 - } 983 - .access-radio input[disabled] { 984 - opacity: 0.5; 985 - pointer-events: none; 986 - } 987 - .access-radio.disabled { 988 - opacity: 0.5; 989 - pointer-events: none; 990 - cursor: not-allowed; 991 115 } 992 116 993 - /* Ensure menu is above nav */ 994 - .header-controls { 995 - position: relative; 996 - } 997 - 998 - /* Responsive: accessibility menu */ 999 - @media (max-width: 650px) { 1000 - .accessibility-menu { 1001 - left: 0.5rem; 1002 - right: 0.5rem; 1003 - top: 3.2rem; 1004 - min-width: unset; 1005 - max-width: calc(100vw - 1rem); 1006 - width: auto; 1007 - border-radius: 1.2rem; 1008 - padding: 0.7rem 0.7rem; 1009 - font-size: 1.05em; 1010 - box-sizing: border-box; 1011 - overflow-x: hidden; 1012 - overflow-y: auto; 1013 - } 1014 - .access-section { 1015 - gap: 0.3rem; 1016 - } 1017 - .access-theme-btns { 1018 - display: flex; 1019 - flex-direction: row; 1020 - gap: 0.5em; 1021 - justify-content: center; 1022 - align-items: center; 1023 - margin-top: 0.3em; 1024 - margin-bottom: 0.2em; 1025 - } 1026 - .access-radio { 1027 - display: inline-flex; 1028 - align-items: center; 1029 - justify-content: center; 1030 - background: var(--btn-bg); 1031 - color: var(--btn-text); 1032 - border: 1.5px solid #c0c0c0; 1033 - border-radius: 999px; 1034 - font-size: 1em; 1035 - font-weight: 600; 1036 - padding: 0.35em 1.1em; 1037 - margin: 0; 1038 - cursor: pointer; 1039 - transition: background 0.15s, color 0.15s, border 0.15s; 1040 - text-align: center; 1041 - min-width: 0; 1042 - min-height: 2.2em; 1043 - box-sizing: border-box; 1044 - flex: 1 1 0; 1045 - outline: none; 1046 - } 1047 - .access-radio.selected, .access-radio:active, .access-radio:focus { 1048 - background: var(--btn-active-bg); 1049 - color: var(--btn-active-text); 1050 - border-color: #222; 1051 - outline: none; 1052 - } 1053 - .access-radio input[type="radio"] { 1054 - display: none; 1055 - } 1056 - .access-textsize button { 1057 - font-size: 1em; 1058 - padding: 0.2em 0.7em; 1059 - } 1060 - } 1061 - 1062 - /* Consistent button style for .access-radio on all screens */ 1063 - .access-radio { 1064 - background: var(--nav-bg); 1065 - color: var(--text-color); 1066 - border: var(--nav-border); 1067 - border-radius: 1.5rem; 1068 - box-shadow: var(--nav-shadow); 1069 - padding: 0.5em 1.5em; 1070 - font-weight: 600; 1071 - font-size: 1em; 1072 - transition: background 0.15s, color 0.15s, box-shadow 0.15s, border 0.15s; 1073 - text-decoration: none; 1074 - display: inline-block; 1075 - outline: none; 1076 - margin: 0 0.2em 0.2em 0; 1077 - cursor: pointer; 1078 - min-width: 0; 1079 - min-height: 2.2em; 1080 - box-sizing: border-box; 1081 - align-items: center; 1082 - justify-content: center; 1083 - } 1084 - .access-radio:hover:not(.selected):not(:active):not(:focus) { 1085 - background: var(--nav-active-bg); 1086 - color: var(--link-hover-color); 1087 - box-shadow: 0 4px 16px rgba(0,0,0,0.10); 1088 - outline: none; 1089 - } 1090 - .dark-theme .access-radio:hover:not(.selected):not(:active):not(:focus) { 1091 - background: var(--nav-active-bg); 1092 - color: #fff; 1093 - } 1094 - .high-contrast .access-radio:hover:not(.selected):not(:active):not(:focus) { 1095 - background: #222 !important; 1096 - color: #00ffff !important; 1097 - } 1098 - .access-radio.selected, .access-radio:active, .access-radio:focus { 1099 - background: var(--nav-active-bg); 1100 - color: var(--link-hover-color); 1101 - box-shadow: 0 4px 16px rgba(0,0,0,0.10); 1102 - border-color: #444; 1103 - outline: none; 1104 - } 1105 - .access-radio input[type="radio"] { 1106 - display: none; 1107 - } 1108 - @media (max-width: 650px) { 1109 - .access-theme-btns { 1110 - display: flex; 1111 - flex-direction: row; 1112 - gap: 0.5em; 1113 - justify-content: center; 1114 - align-items: center; 1115 - margin-top: 0.3em; 1116 - margin-bottom: 0.2em; 1117 - } 1118 - .access-radio { 1119 - width: 100%; 1120 - min-width: 0; 1121 - padding: 0.5em 0.7em; 1122 - font-size: 1em; 1123 - border-radius: 1.5rem; 1124 - margin: 0 0.2em 0.2em 0; 1125 - box-shadow: var(--nav-shadow); 1126 - } 117 + /* Profile section */ 118 + .profile-section { 119 + padding: 1rem; 120 + border-radius: 1rem; 121 + gap: 0.75rem; 122 + display: flex; 123 + flex-direction: column; 124 + align-items: flex-start; 125 + z-index: 10; 1127 126 } 1128 127 1129 - .textsize-round { 1130 - width: 2.1rem; 1131 - height: 2.1rem; 1132 - border-radius: 50%; 1133 - border: 1.5px solid #c0c0c0; 1134 - background: #f7f7f9; 1135 - color: var(--text-color); 1136 - font-size: 1.1em; 1137 - font-weight: bold; 1138 - display: inline-flex; 1139 - align-items: center; 1140 - justify-content: center; 1141 - margin: 0 0.1em; 1142 - cursor: pointer; 1143 - transition: background 0.15s, color 0.15s, border 0.15s; 1144 - } 1145 - .textsize-round:hover, .textsize-round:focus { 1146 - background: #ececf0; 1147 - color: #111; 1148 - border-color: #888; 1149 - outline: none; 1150 - } 1151 - .dark-theme .textsize-round { 1152 - border: 1.5px solid #444a55; 1153 - background: #23242a; 1154 - color: #fff; 1155 - } 1156 - .dark-theme .textsize-round:hover, .dark-theme .textsize-round:focus { 1157 - background: #2d2e36; 1158 - color: #fff; 1159 - border-color: #888; 1160 - } 1161 - .textsize-reset { 1162 - display: inline-flex; 1163 - align-items: center; 1164 - justify-content: center; 1165 - background: none; 1166 - border: none; 1167 - color: var(--link-color); 1168 - font-size: 1em; 128 + /* Profile figure */ 129 + .profile-figure { 130 + gap: 0.75rem; 131 + display: flex; 132 + flex-wrap: wrap; 1169 133 font-weight: 500; 1170 - margin: 0 0.2em; 1171 - cursor: pointer; 1172 - text-decoration: none; 1173 - padding: 0 0.3em; 1174 - min-width: 2.1rem; 1175 - min-height: 2.1rem; 1176 - } 1177 - .textsize-reset:focus, .textsize-reset:hover { 1178 - color: var(--link-hover-color); 1179 - outline: none; 1180 - text-decoration: none; 134 + letter-spacing: -0.0125em; 1181 135 } 1182 136 1183 - /* Visually hidden utility for screen readers */ 1184 - .visually-hidden { 1185 - position: absolute !important; 1186 - width: 1px !important; 1187 - height: 1px !important; 1188 - padding: 0 !important; 1189 - margin: -1px !important; 1190 - overflow: hidden !important; 1191 - clip: rect(0, 0, 0, 0) !important; 1192 - white-space: nowrap !important; 1193 - border: 0 !important; 137 + /* Avatar wrapper */ 138 + .avatar-wrapper { 139 + border-radius: 2rem; 140 + overflow: clip; 141 + aspect-ratio: 1; 142 + color: var(--color-text); 143 + width: 4.75rem; 144 + position: relative; 145 + user-select: none; 1194 146 } 1195 147 1196 - /* Skip link styles */ 1197 - .skip-link { 148 + /* Avatar image */ 149 + .avatar { 150 + max-width: 100%; 1198 151 position: absolute; 1199 - left: 0; 1200 - top: 0; 1201 - background: #ffff00; 1202 - color: #000; 1203 - padding: 0.7em 1.2em; 1204 - z-index: 2000; 1205 - font-weight: bold; 1206 - border-radius: 0 0 8px 0; 1207 - transform: translateY(-120%); 1208 - transition: transform 0.2s; 1209 - outline: 2px solid #000; 1210 - text-decoration: none; 1211 - } 1212 - .skip-link:focus, .skip-link:active { 1213 - transform: translateY(0); 1214 - outline: 4px solid #00ffff; 1215 - background: #000; 1216 - color: #ffff00; 1217 - } 1218 - 1219 - /* High contrast focus outlines for all interactive elements */ 1220 - .high-contrast a, 1221 - .high-contrast button, 1222 - .high-contrast input, 1223 - .high-contrast .btn, 1224 - .high-contrast .menu a, 1225 - .high-contrast .pdf-btn, 1226 - .high-contrast [role="menuitem"], 1227 - .high-contrast [tabindex="0"] { 1228 - outline: 3px solid #ffff00 !important; 1229 - outline-offset: 2px !important; 1230 - box-shadow: none !important; 1231 - } 1232 - .high-contrast a:focus, 1233 - .high-contrast button:focus, 1234 - .high-contrast input:focus, 1235 - .high-contrast .btn:focus, 1236 - .high-contrast .menu a:focus, 1237 - .high-contrast .pdf-btn:focus, 1238 - .high-contrast [role="menuitem"]:focus, 1239 - .high-contrast [tabindex="0"]:focus { 1240 - outline: 4px solid #00ffff !important; 1241 - outline-offset: 2px !important; 1242 - background: #222 !important; 1243 - color: #ffff00 !important; 1244 - } 1245 - 1246 - /* Project media carousel styles */ 1247 - /* Removed carousel styles */ 1248 - 1249 - /* Screenshots grid styling */ 1250 - .screenshots-grid { 1251 - display: grid; 1252 - grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); 1253 - gap: 1rem; 1254 - margin-bottom: 1rem; 1255 - } 1256 - 1257 - .screenshots-grid img { 1258 - width: 100%; 152 + inset-block: 0; 1259 153 height: auto; 1260 - object-fit: cover; 1261 - border-radius: 8px; 1262 - box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); 1263 154 } 1264 155 1265 - /* Screenshots container for mobile carousel */ 1266 - /* Removed carousel styles */ 1267 - 1268 - /* Carousel navigation */ 1269 - /* Removed carousel navigation styles */ 1270 - 1271 - /* Mobile carousel styles for screenshots */ 1272 - /* Removed mobile carousel styles */ 1273 - 1274 - /* Custom scrollbar for mobile carousel */ 1275 - /* Removed custom scrollbar styles */ 1276 - 1277 - /* Show carousel navigation on mobile */ 1278 - /* Removed mobile carousel navigation styles */ 1279 - 1280 - /* App Screenshots Carousel */ 1281 - /* Removed app screenshots carousel styles */ 1282 - 1283 - /* App Store link styling */ 1284 - .app-store-link { 156 + /* Profile caption */ 157 + .profile-caption { 1285 158 display: flex; 159 + flex-direction: column; 1286 160 justify-content: center; 1287 - margin-top: 1rem; 1288 161 } 1289 162 1290 - .app-store-link a { 163 + /* Profile name */ 164 + .profile-name { 165 + color: var(--color-text); 1291 166 display: inline-block; 1292 - text-decoration: none; 1293 - } 1294 - 1295 - .app-store-link img { 1296 - width: 180px; 1297 - height: auto; 1298 - object-fit: contain; 1299 - border-radius: 8px; 1300 - } 1301 - 1302 - /* Responsive adjustments for smaller screens */ 1303 - @media (max-width: 650px) { 1304 - .project-media .carousel { 1305 - gap: 0.5rem; 1306 - } 1307 - .project-media .carousel img { 1308 - width: 70vw; 1309 - } 1310 - 1311 - /* Screenshots grid is now handled by carousel styles above */ 1312 - 1313 - .app-store-badge img { 1314 - height: 40px; 1315 - } 1316 - } 1317 - 1318 - @media (max-width: 650px) { 1319 - header nav { 1320 - display: flex; 1321 - flex-direction: row; 1322 - align-items: center; 1323 - justify-content: space-between; 1324 - min-height: 3.6rem; 1325 - height: 3.6rem; 1326 - position: relative; 1327 - padding-right: 0 !important; 1328 - } 1329 - .brand { 1330 - flex: 1 1 auto; 1331 - text-align: left; 1332 - padding-left: 0.7em; 1333 - } 1334 - .mobile-nav-toggle { 1335 - display: block; 1336 - position: relative; 1337 - z-index: 1002; 1338 - margin-right: 0.5rem; 1339 - margin-left: 0; 1340 - order: 0; 1341 - } 1342 - .header-controls { 1343 - display: flex !important; 1344 - flex: 2 1 auto; 1345 - align-items: center; 1346 - justify-content: flex-end; 1347 - position: static; 1348 - background: none; 1349 - box-shadow: none; 1350 - border: none; 1351 - padding: 0 1rem 0 0; 1352 - gap: 0; 1353 - margin-right: 0 !important; 1354 - } 1355 - .menu { 1356 - display: none; 1357 - } 1358 - .menu.menu-in-bar { 1359 - display: flex !important; 1360 - flex-direction: row !important; 1361 - justify-content: flex-start; 1362 - align-items: center; 1363 - gap: 0; 1364 - width: 100%; 1365 - background: none; 1366 - box-shadow: none; 1367 - border: none; 1368 - margin: 0; 1369 - padding: 0; 1370 - z-index: auto; 1371 - order: 1; 1372 - height: 3.6rem; 1373 - } 1374 - .menu.menu-in-bar li { 1375 - margin: 0; 1376 - padding: 0; 1377 - height: 100%; 1378 - display: flex; 1379 - align-items: center; 1380 - } 1381 - .menu.menu-in-bar a { 1382 - font-size: 1em; 1383 - padding: 0.2em 0.7em; 1384 - margin: 0; 1385 - opacity: 1; 1386 - justify-content: flex-start; 1387 - line-height: 1.2; 1388 - min-height: 2.8rem; 1389 - display: flex; 1390 - align-items: center; 1391 - height: 100%; 1392 - } 1393 - .brand[style*="display: none"] { 1394 - display: none !important; 1395 - } 1396 - .menu.menu-in-bar ~ .header-divider, 1397 - .menu.menu-in-bar ~ #accessibility-btn { 1398 - display: none !important; 1399 - } 1400 - .mobile-nav-toggle { 1401 - order: 2; 1402 - margin-left: 1.2rem; 1403 - margin-right: 0; 1404 - } 167 + font-size: 1.25rem; 168 + font-weight: 600; 169 + letter-spacing: -0.05ch; 170 + width: fit-content; 171 + view-transition-name: author-name; 1405 172 } 1406 173 1407 - /* Add consistent horizontal padding to header bar */ 1408 - header { 1409 - padding-left: 1.2rem; 1410 - padding-right: 1.2rem; 1411 - } 1412 - @media (max-width: 650px) { 1413 - header { 1414 - padding-left: 0.5rem; 1415 - padding-right: 0.5rem; 1416 - } 174 + /* Location wrapper */ 175 + .profile-location-wrapper { 176 + color: var(--color-text-muted); 1417 177 } 1418 178 1419 - header nav, 1420 - header nav.container { 1421 - padding-left: 0 !important; 1422 - padding-right: 0 !important; 1423 - } 1424 - @media (max-width: 650px) { 1425 - header nav, 1426 - header nav.container { 1427 - padding-left: 0 !important; 1428 - padding-right: 0 !important; 1429 - } 1430 - } 1431 - 1432 - .access-section.access-textsize { 1433 - display: flex; 1434 - justify-content: space-between; 179 + /* Location */ 180 + .profile-location { 181 + gap: 0.25rem; 1435 182 align-items: center; 1436 - gap: 1em; 1437 - } 1438 - .access-section.access-textsize .access-label { 1439 - margin-bottom: 0; 1440 - flex: 1 1 auto; 1441 - text-align: left; 1442 - } 1443 - .access-textsize-btns { 1444 183 display: flex; 1445 - gap: 0.3em; 1446 - flex: 0 0 auto; 1447 - align-items: center; 1448 - justify-content: flex-end; 1449 - } 1450 - .brand, .profile-name { 1451 - color: #fff !important; 1452 - text-shadow: 0 1px 8px rgba(0,0,0,0.10); 1453 - } 1454 - 1455 - .dark-theme .brand, .dark-theme .profile-name { 1456 - color: #fff !important; 1457 - } 1458 - 1459 - :root:not(.light-theme):not(.dark-theme) .brand, :root:not(.light-theme):not(.dark-theme) .profile-name { 1460 - color: #fff !important; 1461 - } 1462 - 1463 - /* Modern iOS App Showcase Styles */ 1464 - .ios-app-showcase { 1465 - background: linear-gradient(135deg, #1f1f1f 0%, #2f2f2f 50%, #3f3f3f 100%); 1466 - border-radius: 20px; 1467 - padding: 2rem; 1468 - margin: 2rem 0; 1469 - position: relative; 1470 - overflow: hidden; 184 + font-size: 1rem; 1471 185 } 1472 186 1473 - .ios-app-showcase::before { 1474 - content: ''; 1475 - position: absolute; 1476 - top: 0; 1477 - left: 0; 1478 - right: 0; 1479 - bottom: 0; 1480 - background: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100"><defs><pattern id="grid" width="10" height="10" patternUnits="userSpaceOnUse"><path d="M 10 0 L 0 0 0 10" fill="none" stroke="rgba(255,255,255,0.05)" stroke-width="0.5"/></pattern></defs><rect width="100" height="100" fill="url(%23grid)"/></svg>'); 1481 - opacity: 0.3; 1482 - } 1483 - 1484 - .ios-app-showcase .showcase-content { 1485 - position: relative; 1486 - z-index: 2; 1487 - } 1488 - 1489 - .ios-app-showcase h3 { 1490 - color: white; 1491 - font-size: 1.8rem; 1492 - margin: 0 0 1rem 0; 1493 - font-weight: 600; 1494 - } 1495 - 1496 - .ios-app-showcase .app-description { 1497 - color: rgba(255, 255, 255, 0.9); 1498 - margin-bottom: 2rem; 1499 - line-height: 1.6; 1500 - } 1501 - 1502 - /* Device Mockup Container */ 1503 - .device-showcase { 1504 - display: flex; 1505 - align-items: center; 1506 - justify-content: center; 1507 - gap: 2rem; 1508 - margin: 2rem 0; 1509 - } 1510 - 1511 - /* iPhone Mockup */ 1512 - .iphone-mockup { 1513 - position: relative; 1514 - width: 240px; 1515 - height: 521px; 1516 - background: #1a1a1a; 1517 - border-radius: 40px; 1518 - padding: 8px; 1519 - box-shadow: 1520 - 0 20px 40px rgba(0, 0, 0, 0.3), 1521 - 0 0 0 1px rgba(255, 255, 255, 0.1) inset; 1522 - transform: perspective(1000px) rotateY(-15deg) rotateX(5deg); 1523 - transition: transform 0.3s ease; 1524 - } 1525 - 1526 - .iphone-mockup:hover { 1527 - transform: perspective(1000px) rotateY(-10deg) rotateX(2deg) scale(1.02); 1528 - } 1529 - 1530 - .iphone-mockup .screen { 1531 - width: 100%; 1532 - height: 100%; 1533 - border-radius: 32px; 1534 - overflow: hidden; 1535 - position: relative; 1536 - background: #000; 1537 - } 1538 - 1539 - .iphone-mockup .screen img { 1540 - width: 100%; 1541 - height: 100%; 1542 - object-fit: cover; 1543 - border-radius: 32px; 1544 - } 1545 - 1546 - /* App Screenshots Carousel */ 1547 - /* Removed app screenshots carousel styles */ 1548 - 1549 - /* App Store Badge */ 1550 - .app-store-section { 1551 - text-align: center; 1552 - margin-top: 2rem; 1553 - } 1554 - 1555 - .app-store-badge { 187 + /* Location icon */ 188 + .location-icon { 189 + height: 1rem; 1556 190 display: inline-block; 1557 - text-decoration: none; 1558 - transition: transform 0.3s ease; 1559 - } 1560 - 1561 - .app-store-badge:hover { 1562 - transform: translateY(-2px); 1563 - } 1564 - 1565 - .app-store-badge img { 1566 - height: 50px; 1567 191 width: auto; 1568 192 } 1569 193 1570 - /* Feature Highlights */ 1571 - .app-features { 1572 - display: grid; 1573 - grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); 1574 - gap: 1.5rem; 1575 - margin: 2rem 0; 194 + /* VT logo specific sizing */ 195 + .vt-logo { 196 + height: 0.9rem; 197 + width: auto; 1576 198 } 1577 199 1578 - .feature-card { 1579 - background: rgba(255, 255, 255, 0.1); 1580 - border: 1px solid rgba(255, 255, 255, 0.2); 1581 - border-radius: 15px; 1582 - padding: 1.5rem; 1583 - backdrop-filter: blur(10px); 1584 - transition: all 0.3s ease; 200 + .vt-path { 201 + fill: var(--color-bg); 202 + stroke: currentColor; 203 + stroke-width: 8; 1585 204 } 1586 205 1587 - .feature-card:hover { 1588 - background: rgba(255, 255, 255, 0.15); 1589 - transform: translateY(-3px); 1590 - } 1591 - 1592 - .feature-card h4 { 1593 - color: white; 1594 - margin: 0 0 0.5rem 0; 1595 - font-size: 1.2rem; 1596 - } 1597 - 1598 - .feature-card p { 1599 - color: rgba(255, 255, 255, 0.8); 1600 - margin: 0; 1601 - font-size: 0.9rem; 1602 - line-height: 1.5; 1603 - } 1604 - 1605 - /* Stats Section */ 1606 - .app-stats { 206 + /* Social links */ 207 + .social-links { 208 + gap: 0.5ch; 1607 209 display: flex; 1608 - justify-content: space-around; 1609 - margin: 2rem 0; 1610 - flex-wrap: nowrap; 1611 - gap: 1rem; 1612 - } 1613 - 1614 - .stat-item { 1615 - text-align: center; 1616 - color: white; 1617 - } 1618 - 1619 - .stat-number { 1620 - font-size: 2rem; 1621 - font-weight: 700; 1622 - display: block; 1623 - margin-bottom: 0.25rem; 1624 - } 1625 - 1626 - .stat-label { 1627 - font-size: 0.9rem; 1628 - opacity: 0.8; 1629 - } 1630 - 1631 - /* Dark theme adjustments */ 1632 - .dark-theme .ios-app-showcase { 1633 - background: linear-gradient(135deg, #151515 0%, #1f1f1f 50%, #2f2f2f 100%); 1634 - } 1635 - 1636 - /* Mobile Responsive */ 1637 - @media (max-width: 768px) { 1638 - .ios-app-showcase { 1639 - padding: 1.5rem; 1640 - margin: 1rem 0; 1641 - } 1642 - 1643 - .device-showcase { 1644 - flex-direction: column; 1645 - gap: 1rem; 1646 - } 1647 - 1648 - .iphone-mockup { 1649 - width: 200px; 1650 - height: 434px; 1651 - transform: none; 1652 - } 1653 - 1654 - .iphone-mockup:hover { 1655 - transform: scale(1.02); 1656 - } 1657 - 1658 - .app-screenshots { 1659 - gap: 1rem; 1660 - justify-content: flex-start; 1661 - margin-left: calc(-1 * (100vw - 100%) / 2); 1662 - margin-right: calc(-1 * (100vw - 100%) / 2); 1663 - padding-left: calc((100vw - 100%) / 2); 1664 - padding-right: calc((100vw - 100%) / 2); 1665 - } 1666 - 1667 - .app-screenshots .screenshot-item img { 1668 - width: 180px; 1669 - height: 391px; 1670 - } 1671 - 1672 - .app-features { 1673 - grid-template-columns: 1fr; 1674 - } 1675 - 1676 - .app-stats { 1677 - flex-direction: row; 1678 - align-items: center; 1679 - } 1680 - } 1681 - 1682 - @media (max-width: 480px) { 1683 - .ios-app-showcase h3 { 1684 - font-size: 1.5rem; 1685 - } 1686 - 1687 - .iphone-mockup { 1688 - width: 160px; 1689 - height: 347px; 1690 - } 1691 - 1692 - .app-screenshots { 1693 - justify-content: flex-start; 1694 - margin-left: calc(-1 * (100vw - 100%) / 2); 1695 - margin-right: calc(-1 * (100vw - 100%) / 2); 1696 - padding-left: calc((100vw - 100%) / 2); 1697 - padding-right: calc((100vw - 100%) / 2); 1698 - } 1699 - 1700 - .app-screenshots .screenshot-item img { 1701 - width: 160px; 1702 - height: 347px; 1703 - } 1704 - } 1705 - 1706 - /* Animation for showcase entrance */ 1707 - @keyframes showcaseFadeIn { 1708 - from { 1709 - opacity: 0; 1710 - transform: translateY(30px); 1711 - } 1712 - to { 1713 - opacity: 1; 1714 - transform: translateY(0); 1715 - } 1716 - } 1717 - 1718 - .ios-app-showcase { 1719 - animation: showcaseFadeIn 0.6s ease-out; 1720 - } 1721 - 1722 - /* Hover effects for interactive elements */ 1723 - .ios-app-showcase .screenshot-item { 1724 - cursor: pointer; 1725 - } 1726 - 1727 - .ios-app-showcase .screenshot-item:active img { 1728 - transform: scale(0.98); 1729 - } 1730 - 1731 - /* Loading state for images */ 1732 - .ios-app-showcase img { 1733 - transition: opacity 0.3s ease; 1734 - } 1735 - 1736 - .ios-app-showcase img[loading] { 1737 - opacity: 0.7; 1738 - } 1739 - 1740 - /* Accessibility improvements */ 1741 - .ios-app-showcase .app-store-badge:focus { 1742 - outline: 2px solid rgba(255, 255, 255, 0.8); 1743 - outline-offset: 2px; 1744 - } 1745 - 1746 - /* High contrast mode support */ 1747 - .high-contrast .ios-app-showcase { 1748 - background: #000; 1749 - border: 2px solid #fff; 1750 - } 1751 - 1752 - .high-contrast .ios-app-showcase .feature-card { 1753 - background: #fff; 1754 - color: #000; 1755 - border: 2px solid #000; 1756 - } 1757 - 1758 - .high-contrast .ios-app-showcase .feature-card h4 { 1759 - color: #000; 1760 - } 1761 - 1762 - .high-contrast .ios-app-showcase .feature-card p { 1763 - color: #333; 1764 - } 1765 - 1766 - /* High contrast mode support for Yik Yak Virginia Tech panel */ 1767 - .high-contrast .vt-yikyak-showcase { 1768 - background: #000; 1769 - border: 2px solid #fff; 1770 - } 1771 - 1772 - .high-contrast .vt-yikyak-showcase h3 { 1773 - color: #fff; 1774 - } 1775 - 1776 - .high-contrast .vt-yikyak-showcase .app-description { 1777 - color: #fff; 1778 - } 1779 - 1780 - .high-contrast .vt-yikyak-showcase .profile-picture { 1781 - border: 2px solid #fff; 1782 - } 1783 - 1784 - .high-contrast .vt-yikyak-showcase .title-section h3 { 1785 - color: #fff; 1786 - } 1787 - 1788 - .high-contrast .vt-yikyak-showcase .title-section .subtitle { 1789 - color: #fff; 1790 - } 1791 - 1792 - .high-contrast .vt-yikyak-showcase .content-section h4 { 1793 - color: #fff; 1794 - } 1795 - 1796 - .high-contrast .vt-yikyak-showcase .content-section p { 1797 - color: #fff; 1798 - } 1799 - 1800 - .high-contrast .vt-yikyak-showcase .feature-card { 1801 - background: #fff; 1802 - color: #000; 1803 - border: 2px solid #000; 1804 - } 1805 - 1806 - .high-contrast .vt-yikyak-showcase .feature-card h4 { 1807 - color: #000; 1808 - } 1809 - 1810 - .high-contrast .vt-yikyak-showcase .feature-card p { 1811 - color: #333; 1812 - } 1813 - 1814 - .high-contrast .vt-yikyak-showcase .stat-item { 1815 - color: #fff; 1816 - } 1817 - 1818 - .high-contrast .vt-yikyak-showcase .stat-number { 1819 - color: #fff; 1820 - } 1821 - 1822 - .high-contrast .vt-yikyak-showcase .stat-label { 1823 - color: #fff; 1824 - } 1825 - 1826 - .high-contrast .vt-yikyak-showcase .content-section img { 1827 - border: 2px solid #fff; 1828 - } 1829 - 1830 - /* Yik Yak Project Specific Styles */ 1831 - .profile-header { 1832 - display: flex; 1833 - align-items: center; 1834 - gap: 1.5rem; 1835 - margin-bottom: 1.5rem; 1836 - } 1837 - 1838 - .profile-picture { 1839 - width: 120px; 1840 - height: 120px; 1841 - border-radius: 50%; 1842 - object-fit: cover; 1843 - transition: transform 0.3s ease; 1844 - flex-shrink: 0; 1845 - } 1846 - 1847 - .profile-picture:hover { 1848 - transform: scale(1.05); 1849 - } 1850 - 1851 - .title-section { 1852 - display: flex; 1853 - flex-direction: column; 1854 - gap: 0.1rem; 1855 - } 1856 - 1857 - .title-section h3 { 1858 - margin: 0; 1859 - font-size: 1.8em; 1860 - color: var(--text-color); 1861 - } 1862 - 1863 - .title-section .subtitle { 1864 - margin: 0; 1865 - font-size: 1.1em; 1866 - color: var(--link-color); 1867 - opacity: 0.8; 1868 - } 1869 - 1870 - .content-section { 1871 - margin: 2rem 0; 1872 - } 1873 - 1874 - .content-section h4 { 1875 - font-size: 1.3em; 1876 - margin-bottom: 1rem; 1877 - color: var(--text-color); 1878 - text-align: center; 1879 - } 1880 - 1881 - .section-title-left { 1882 - text-align: left !important; 1883 - display: block; 1884 - } 1885 - 1886 - @media (max-width: 768px) { 1887 - .profile-header { 1888 - gap: 1rem; 1889 - } 1890 - 1891 - .profile-picture { 1892 - width: 80px; 1893 - height: 80px; 1894 - } 1895 - 1896 - .title-section h3 { 1897 - font-size: 1.5em; 1898 - } 1899 - 1900 - .title-section .subtitle { 1901 - font-size: 1em; 1902 - } 1903 - 1904 - .content-section h4 { 1905 - font-size: 1.1em; 1906 - } 1907 - } 1908 - 1909 - /* VT Yik Yak Showcase Styles */ 1910 - .vt-yikyak-showcase { 1911 - background: linear-gradient(135deg, var(--vt-maroon) 0%, var(--vt-impactOrange) 100%); 1912 - border-radius: 22px; 1913 - padding: 2.2rem 2rem; 1914 - margin: 2.5rem 0; 1915 - position: relative; 1916 - overflow: hidden; 1917 - box-shadow: 0 6px 32px rgba(134,31,65,0.18); 1918 - } 1919 - .vt-yikyak-showcase .showcase-content { 1920 - position: relative; 1921 - z-index: 2; 1922 - } 1923 - .vt-yikyak-showcase h3 { 1924 - color: var(--vt-burntOrange); 1925 - font-size: 2rem; 1926 - margin: 0 0 1.1rem 0; 1927 - font-weight: 700; 1928 - letter-spacing: 1px; 1929 - } 1930 - .vt-yikyak-showcase .app-description { 1931 - color: var(--vt-white); 1932 - margin-bottom: 2rem; 1933 - line-height: 1.7; 1934 - font-size: 1.08em; 1935 - } 1936 - .vt-yikyak-showcase .profile-header { 1937 - display: flex; 1938 - align-items: center; 1939 - gap: 1.7rem; 1940 - margin-bottom: 1.7rem; 1941 - } 1942 - .vt-yikyak-showcase .profile-picture { 1943 - width: 120px; 1944 - height: 120px; 1945 - border-radius: 50%; 1946 - object-fit: cover; 1947 - border: 4px solid var(--vt-burntOrange); 1948 - background: var(--vt-white); 1949 - box-shadow: 0 2px 12px rgba(229,117,31,0.13); 1950 - transition: transform 0.3s; 1951 - } 1952 - .vt-yikyak-showcase .profile-picture:hover { 1953 - transform: scale(1.06); 1954 - } 1955 - .vt-yikyak-showcase .title-section h3 { 1956 - color: var(--vt-burntOrange); 1957 - font-size: 2em; 1958 - margin: 0; 1959 - } 1960 - .vt-yikyak-showcase .title-section .subtitle { 1961 - color: var(--vt-yellow); 1962 - font-size: 1.1em; 1963 - opacity: 0.95; 1964 - margin: 0; 1965 - } 1966 - .vt-yikyak-showcase .content-section h4 { 1967 - color: var(--vt-impactOrange); 1968 - font-size: 1.25em; 1969 - margin-bottom: 1rem; 1970 - text-align: center; 1971 - letter-spacing: 0.5px; 1972 - } 1973 - .vt-yikyak-showcase .app-screenshots .screenshot-item img { 1974 - border-radius: 18px; 1975 - border: none; 1976 - box-shadow: none; 1977 - } 1978 - .vt-yikyak-showcase .feature-card { 1979 - background: none; 1980 - border: none; 1981 - border-radius: 15px; 1982 - padding: 1.3rem; 1983 - color: var(--vt-white); 1984 - box-shadow: 0 2px 10px rgba(134,31,65,0.10); 1985 - transition: background 0.3s, color 0.3s, border 0.3s; 1986 - } 1987 - .vt-yikyak-showcase .feature-card:hover { 1988 - background: rgba(134,31,65,0.12); 1989 - color: var(--vt-white); 1990 - border: none; 1991 - } 1992 - .vt-yikyak-showcase .feature-card h4 { 1993 - color: var(--vt-yellow); 1994 - margin: 0 0 0.5rem 0; 1995 - font-size: 1.15rem; 1996 - } 1997 - .vt-yikyak-showcase .feature-card p { 1998 - color: var(--vt-white); 1999 - font-size: 0.97rem; 210 + flex-wrap: wrap; 211 + font-size: 0.94em; 212 + max-width: 25rem; 213 + list-style: none; 2000 214 margin: 0; 2001 - } 2002 - .vt-yikyak-showcase .feature-card:hover { 2003 - background: linear-gradient(120deg, var(--vt-maroon) 0%, var(--vt-burntOrange) 100%); 2004 - color: var(--vt-yellow); 2005 - border-color: var(--vt-impactOrange); 2006 - } 2007 - .vt-yikyak-showcase .app-stats { 2008 - display: flex; 2009 - justify-content: space-around; 2010 - margin: 2rem 0 0.5rem 0; 2011 - flex-wrap: nowrap; 2012 - gap: 1.2rem; 2013 - } 2014 - .vt-yikyak-showcase .stat-item { 2015 - text-align: center; 2016 - color: var(--vt-yellow); 2017 - } 2018 - .vt-yikyak-showcase .stat-number { 2019 - font-size: 2.1rem; 2020 - font-weight: 800; 2021 - display: block; 2022 - margin-bottom: 0.2rem; 2023 - color: var(--vt-burntOrange); 2024 - } 2025 - .vt-yikyak-showcase .stat-label { 2026 - font-size: 1rem; 2027 - opacity: 0.9; 2028 - color: var(--vt-yellow); 2029 - } 2030 - .vt-yikyak-showcase .content-section { 2031 - margin: 2rem 0; 2032 - background: none; 2033 - border-radius: 0; 2034 215 padding: 0; 2035 216 } 2036 - @media (max-width: 768px) { 2037 - .vt-yikyak-showcase { 2038 - padding: 1.2rem 0.5rem; 2039 - } 2040 - .vt-yikyak-showcase .profile-header { 2041 - gap: 1rem; 2042 - } 2043 - .vt-yikyak-showcase .profile-picture { 2044 - width: 80px; 2045 - height: 80px; 2046 - } 2047 - .vt-yikyak-showcase .title-section h3 { 2048 - font-size: 1.3em; 2049 - } 2050 - .vt-yikyak-showcase .title-section .subtitle { 2051 - font-size: 1em; 2052 - } 2053 - .vt-yikyak-showcase .content-section h4 { 2054 - font-size: 1.1em; 2055 - } 2056 - } 2057 - .vt-yikyak-showcase, 2058 - .vt-yikyak-showcase h3, 2059 - .vt-yikyak-showcase .app-description, 2060 - .vt-yikyak-showcase .profile-header, 2061 - .vt-yikyak-showcase .title-section h3, 2062 - .vt-yikyak-showcase .title-section .subtitle, 2063 - .vt-yikyak-showcase .content-section h4, 2064 - .vt-yikyak-showcase .feature-card, 2065 - .vt-yikyak-showcase .feature-card h4, 2066 - .vt-yikyak-showcase .feature-card p, 2067 - .vt-yikyak-showcase .stat-item, 2068 - .vt-yikyak-showcase .stat-number, 2069 - .vt-yikyak-showcase .stat-label { 2070 - color: var(--vt-white) !important; 2071 - } 2072 - .rounded-image { 2073 - border-radius: 20px; 2074 - overflow: hidden; 2075 - } 2076 217 2077 - /* VT Gym Tracker Carousel Controls */ 2078 - .app-screenshots { 2079 - position: relative; 2080 - display: flex; 218 + /* Social link */ 219 + .social-link { 220 + border-color: var(--color-border); 221 + border-radius: 9999px; 222 + border-style: solid; 223 + border-width: 0.9px; 224 + gap: 0.6ch; 225 + padding-block: 0.5ch; 226 + padding-inline: 1ch; 227 + text-decoration: none; 2081 228 align-items: center; 229 + color: var(--color-text); 230 + display: inline-flex; 2082 231 justify-content: center; 2083 - gap: 0.5rem; 2084 - min-height: 420px; 232 + letter-spacing: -0.01ch; 233 + transition: color 0.2s cubic-bezier(0.25, 0.1, 0.25, 1.3), transform 0.2s cubic-bezier(0.25, 0.1, 0.25, 1.3); 2085 234 } 2086 - .app-screenshots .screenshot-item { 2087 - flex: 1 1 auto; 2088 - display: none; 2089 - justify-content: center; 2090 - align-items: center; 2091 - text-align: center; 235 + 236 + .social-link:hover { 237 + color: var(--color-text); 2092 238 } 2093 - .app-screenshots .screenshot-item img { 2094 - max-width: 220px; 2095 - max-height: 420px; 2096 - width: 100%; 2097 - height: auto; 2098 - border-radius: 18px; 2099 - box-shadow: 0 2px 12px rgba(0,0,0,0.10); 2100 - background: #fff; 239 + 240 + .social-link:active { 241 + color: var(--color-text); 242 + transform: scale(0.9); 2101 243 } 2102 - .carousel-btn { 2103 - background: var(--btn-bg); 2104 - color: var(--btn-text); 2105 - border: 1.5px solid #bbb; 2106 - border-radius: 50%; 2107 - width: 2.5rem; 2108 - height: 2.5rem; 2109 - font-size: 1.5rem; 2110 - display: flex; 244 + 245 + /* Social icon wrapper */ 246 + .social-icon-wrapper { 2111 247 align-items: center; 2112 - justify-content: center; 2113 - cursor: pointer; 2114 - transition: background 0.15s, color 0.15s, border 0.15s; 2115 - z-index: 2; 2116 - margin: 0 0.5rem; 2117 - } 2118 - .carousel-btn:hover, .carousel-btn:focus { 2119 - background: var(--btn-bg-hover); 2120 - color: var(--btn-active-text); 2121 - border-color: #888; 2122 - outline: none; 2123 - } 2124 - .carousel-dots { 248 + height: 1rem; 2125 249 display: flex; 250 + width: 1rem; 2126 251 justify-content: center; 2127 - align-items: center; 2128 - gap: 0.5rem; 2129 - margin-top: 1rem; 2130 - width: 100%; 2131 - position: absolute; 2132 - bottom: 0.5rem; 2133 - left: 0; 2134 - } 2135 - .carousel-dot { 2136 - width: 0.9rem; 2137 - height: 0.9rem; 2138 - border-radius: 50%; 2139 - background: #bbb; 2140 - border: none; 2141 - cursor: pointer; 2142 - transition: background 0.2s, box-shadow 0.2s; 2143 - outline: none; 2144 - margin: 0 0.1rem; 2145 - padding: 0; 2146 - } 2147 - .carousel-dot.active, .carousel-dot:focus { 2148 - background: var(--btn-active-bg); 2149 - box-shadow: 0 0 0 2px var(--btn-active-underline); 2150 - } 2151 - @media (max-width: 650px) { 2152 - .app-screenshots { 2153 - min-height: 260px; 2154 - } 2155 - .app-screenshots .screenshot-item img { 2156 - max-width: 120px; 2157 - max-height: 260px; 2158 - } 2159 252 } 2160 253 2161 - /* VT Gym Tracker Horizontal Screenshot List */ 2162 - .app-screenshots { 2163 - display: flex; 2164 - flex-direction: row; 2165 - gap: 1.2rem; 2166 - align-items: flex-start; 2167 - justify-content: flex-start; 2168 - overflow-x: auto; 2169 - padding-bottom: 0.5rem; 2170 - min-height: unset; 2171 - position: relative; 2172 - } 2173 - .app-screenshots .screenshot-item { 2174 - flex: 0 0 auto; 2175 - display: block !important; 2176 - align-items: center; 2177 - justify-content: center; 2178 - text-align: center; 2179 - } 2180 - .app-screenshots .screenshot-item img { 2181 - max-width: 220px; 2182 - max-height: 420px; 2183 - width: 100%; 2184 - height: auto; 2185 - border-radius: 18px; 2186 - box-shadow: 0 2px 12px rgba(0,0,0,0.10); 2187 - background: #fff; 2188 - margin: 0; 2189 - } 2190 - @media (max-width: 650px) { 2191 - .app-screenshots { 2192 - gap: 0.7rem; 2193 - padding-bottom: 0.3rem; 2194 - } 2195 - .app-screenshots .screenshot-item img { 2196 - max-width: 120px; 2197 - max-height: 260px; 2198 - } 2199 - } 2200 - 2201 - /* Old Burying Ground image sizing */ 2202 - .allentown-media .carousel img { 2203 - max-width: 400px; 2204 - width: 100%; 2205 - height: auto; 2206 - display: block; 2207 - margin: 0 auto; 2208 - border-radius: 16px; 2209 - box-shadow: 0 2px 12px rgba(0,0,0,0.10); 2210 - } 2211 - @media (max-width: 650px) { 2212 - .allentown-media .carousel img { 2213 - max-width: 95vw; 2214 - } 2215 - } 2216 - 2217 - /* Yik Yak panel image sizing */ 2218 - .vt-yikyak-showcase .content-section img { 2219 - max-width: 260px; 2220 - width: 100%; 2221 - height: auto; 2222 - margin: 0 auto; 2223 - border-radius: 14px; 2224 - box-shadow: 0 2px 8px rgba(0,0,0,0.08); 2225 - display: block; 2226 - } 2227 - @media (max-width: 650px) { 2228 - .vt-yikyak-showcase .content-section img { 2229 - max-width: 90vw; 2230 - } 254 + /* Social icon */ 255 + .social-icon { 256 + fill: currentColor; 257 + height: 1.618cap; 258 + flex-shrink: 0; 259 + width: auto; 2231 260 } 2232 261 2233 - /* Safari fix: prevent flex children from shrinking in horizontal scroll */ 2234 - .app-screenshots .screenshot-item { 2235 - flex-shrink: 0; 262 + .social-icon-stroke { 263 + fill: none; 264 + stroke: currentColor; 2236 265 } 2237 266 2238 - /* Safari/iOS fix: smooth horizontal scrolling */ 2239 - .app-screenshots { 2240 - -webkit-overflow-scrolling: touch; 267 + /* Social label */ 268 + .social-label { 269 + user-select: none; 2241 270 } 2242 271 2243 - /* Ensure social icons are visible and not collapsed */ 2244 - .social-links a, .social-links svg { 2245 - color: #333; 2246 - min-width: 1.2rem; 2247 - min-height: 1.2rem; 272 + /* Orbyt icon - white PNG needs color adjustment */ 273 + .orbyt-icon { 274 + filter: invert(1); 2248 275 } 2249 276 2250 277 @media (prefers-color-scheme: dark) { 2251 - .social-links a, .social-links svg { 2252 - color: #fff; 278 + .orbyt-icon { 279 + filter: none; 2253 280 } 2254 281 } 2255 282 2256 - /* Privacy Policy Page Styles */ 2257 - .privacy-policy { 2258 - max-width: 800px; 2259 - margin: 0 auto; 2260 - line-height: 1.7; 2261 - padding: 2rem 1rem; 2262 - /* Improve readability with better spacing */ 2263 - letter-spacing: 0.01em; 2264 - } 2265 283 2266 - /* Enhanced typography for better hierarchy */ 2267 - .privacy-policy h1 { 2268 - font-size: clamp(2rem, 5vw, 2.5rem); 2269 - margin: 0 0 1.5rem 0; 2270 - color: var(--text-color); 2271 - text-align: left; 2272 - font-weight: 700; 2273 - letter-spacing: -0.02em; 2274 - } 2275 - 2276 - .privacy-policy h2 { 2277 - font-size: clamp(1.4rem, 4vw, 1.8rem); 2278 - margin: 2rem 0 1rem 0; 2279 - color: var(--text-color); 2280 - font-weight: 600; 2281 - letter-spacing: -0.01em; 2282 - } 2283 - 2284 - .privacy-policy p { 2285 - margin-bottom: 1.2rem; 2286 - color: var(--text-color); 2287 - font-size: clamp(1rem, 2.5vw, 1.1rem); 284 + /* View transition */ 285 + @view-transition { 286 + navigation: auto; 2288 287 } 2289 288 2290 - .privacy-policy a { 2291 - color: var(--vt-maroon); 2292 - text-decoration: none; 2293 - transition: color 0.2s ease; 289 + ::view-transition-group(*) { 290 + animation-timing-function: cubic-bezier(0.2, 0.8, 0.2, 1); 2294 291 } 2295 292 2296 - .privacy-policy a:hover { 2297 - color: var(--vt-burntOrange); 293 + ::view-transition-old(*) { 294 + animation-timing-function: cubic-bezier(0.4, 0, 1, 1); 2298 295 } 2299 296 2300 - .app-icon-container { 2301 - display: flex; 2302 - justify-content: flex-start; 2303 - margin-bottom: 1rem; 2304 - padding: 0.5rem 0; 297 + ::view-transition-new(*) { 298 + animation-timing-function: cubic-bezier(0, 0, 0.2, 1); 2305 299 } 2306 - 2307 - .app-icon-container a { 2308 - display: inline-block; 2309 - text-decoration: none; 2310 - border-radius: inherit; 2311 - } 2312 - 2313 - .app-icon { 2314 - /* Use clamp() for fluid sizing that scales with screen size */ 2315 - width: clamp(100px, 8vw, 140px); 2316 - height: clamp(100px, 8vw, 140px); 2317 - border-radius: clamp(20px, 2vw, 28px); 2318 - box-shadow: 0 6px 24px rgba(0, 0, 0, 0.12); 2319 - transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); 2320 - /* Ensure proper aspect ratio and prevent distortion */ 2321 - object-fit: cover; 2322 - /* Add subtle border for better definition */ 2323 - border: 2px solid rgba(255, 255, 255, 0.1); 2324 - } 2325 - 2326 - .app-icon:hover { 2327 - transform: scale(1.08) translateY(-2px); 2328 - box-shadow: 0 12px 32px rgba(0, 0, 0, 0.18); 2329 - } 2330 - 2331 - /* Focus state for accessibility */ 2332 - .app-icon:focus { 2333 - outline: 3px solid var(--vt-maroon); 2334 - outline-offset: 4px; 2335 - } 2336 - 2337 - /* Ensure minimum touch target size for mobile */ 2338 - @media (max-width: 768px) { 2339 - .app-icon { 2340 - min-width: 44px; 2341 - min-height: 44px; 2342 - } 2343 - } 2344 - 2345 - /* High contrast mode support */ 2346 - @media (prefers-contrast: high) { 2347 - .app-icon { 2348 - border: 2px solid currentColor; 2349 - } 2350 - 2351 - .app-icon:hover { 2352 - border-color: var(--vt-maroon); 2353 - } 2354 - } 2355 - 2356 - /* Reduced motion support */ 2357 - @media (prefers-reduced-motion: reduce) { 2358 - .app-icon { 2359 - transition: none; 2360 - } 2361 - 2362 - .app-icon:hover { 2363 - transform: none; 2364 - } 2365 - } 2366 - 2367 - 2368 - 2369 - .privacy-policy h3 { 2370 - font-size: 1.3em; 2371 - margin: 1.5rem 0 0.8rem 0; 2372 - color: var(--link-color); 2373 - } 2374 - 2375 - .privacy-policy p { 2376 - margin: 0.8rem 0 1.2rem 0; 2377 - color: var(--text-color); 2378 - } 2379 - 2380 - .privacy-policy ul { 2381 - margin: 0.8rem 0 1.2rem 0; 2382 - padding-left: 1.5rem; 2383 - } 2384 - 2385 - .privacy-policy li { 2386 - margin-bottom: 0.5rem; 2387 - color: var(--text-color); 2388 - } 2389 - 2390 - .privacy-policy strong { 2391 - color: var(--link-hover-color); 2392 - font-weight: 600; 2393 - } 2394 - 2395 - .privacy-policy a { 2396 - color: var(--vt-maroon); 2397 - text-decoration: underline; 2398 - transition: color 0.15s; 2399 - } 2400 - 2401 - .privacy-policy a:hover, 2402 - .privacy-policy a:focus { 2403 - color: var(--vt-burntOrange); 2404 - text-decoration: underline; 2405 - } 2406 - 2407 - .privacy-policy em { 2408 - font-style: italic; 2409 - color: var(--link-color); 2410 - opacity: 0.9; 2411 - } 2412 - 2413 - /* Responsive design with modern breakpoints */ 2414 - /* Large screens (1200px+) */ 2415 - @media (min-width: 1200px) { 2416 - .app-icon { 2417 - width: clamp(120px, 6vw, 160px); 2418 - height: clamp(120px, 6vw, 160px); 2419 - } 2420 - 2421 - .app-icon-container { 2422 - margin-bottom: 1.5rem; 2423 - } 2424 - } 2425 - 2426 - /* Tablets and small desktops (768px - 1199px) */ 2427 - @media (min-width: 768px) and (max-width: 1199px) { 2428 - .app-icon { 2429 - width: clamp(100px, 7vw, 130px); 2430 - height: clamp(100px, 7vw, 130px); 2431 - } 2432 - 2433 - .app-icon-container { 2434 - margin-bottom: 1.25rem; 2435 - } 2436 - } 2437 - 2438 - /* Mobile landscape and small tablets (481px - 767px) */ 2439 - @media (min-width: 481px) and (max-width: 767px) { 2440 - .app-icon { 2441 - width: clamp(80px, 8vw, 110px); 2442 - height: clamp(80px, 8vw, 110px); 2443 - } 2444 - 2445 - .app-icon-container { 2446 - margin-bottom: 1rem; 2447 - padding: 0.5rem 0; 2448 - } 2449 - 2450 - .privacy-policy h1 { 2451 - font-size: clamp(1.8em, 4vw, 2.2em); 2452 - } 2453 - 2454 - .privacy-policy h2 { 2455 - font-size: clamp(1.4em, 3.5vw, 1.8em); 2456 - margin: 1.5rem 0 0.8rem 0; 2457 - } 2458 - } 2459 - 2460 - /* Mobile portrait (320px - 480px) */ 2461 - @media (max-width: 480px) { 2462 - .app-icon { 2463 - width: clamp(70px, 12vw, 90px); 2464 - height: clamp(70px, 12vw, 90px); 2465 - border-radius: clamp(16px, 3vw, 20px); 2466 - } 2467 - 2468 - .app-icon-container { 2469 - margin-bottom: 0.75rem; 2470 - padding: 0.25rem 0; 2471 - } 2472 - 2473 - .privacy-policy h1 { 2474 - font-size: clamp(1.6em, 5vw, 2em); 2475 - margin: 0 0 0.8rem 0; 2476 - } 2477 - 2478 - .privacy-policy h2 { 2479 - font-size: clamp(1.3em, 4vw, 1.6em); 2480 - margin: 1.2rem 0 0.6rem 0; 2481 - } 2482 - 2483 - .privacy-policy p { 2484 - font-size: clamp(0.9em, 3.5vw, 1em); 2485 - margin-bottom: 1rem; 2486 - line-height: 1.6; 2487 - } 2488 - 2489 - .privacy-policy { 2490 - padding: 1rem; 2491 - margin: 0.5rem; 2492 - } 2493 - } 2494 - 2495 - /* Extra small screens (below 320px) */ 2496 - @media (max-width: 319px) { 2497 - .app-icon { 2498 - width: 60px; 2499 - height: 60px; 2500 - border-radius: 14px; 2501 - } 2502 - 2503 - .app-icon-container { 2504 - margin-bottom: 0.5rem; 2505 - padding: 0.125rem 0; 2506 - } 2507 - 2508 - .privacy-policy { 2509 - padding: 0.75rem; 2510 - margin: 0.25rem; 2511 - } 2512 - } 2513 - 2514 - /* Social Icons Styles (outside footer) */ 2515 - .social-icons { 2516 - display: flex; 2517 - justify-content: center; 2518 - align-items: center; 2519 - gap: 1rem; 2520 - margin: 2rem 0; 2521 - padding: 1rem 0; 2522 - } 2523 - 2524 - .social-icons a { 2525 - display: flex; 2526 - align-items: center; 2527 - justify-content: center; 2528 - width: 3rem; 2529 - height: 3rem; 2530 - border-radius: 50%; 2531 - background: transparent; 2532 - color: var(--text-color); 2533 - text-decoration: none; 2534 - transition: all 0.2s ease; 2535 - border: none; 2536 - /* Ensure minimum touch target size for accessibility */ 2537 - min-width: 44px; 2538 - min-height: 44px; 2539 - } 2540 - 2541 - .social-icons a:hover, 2542 - .social-icons a:focus { 2543 - background: transparent; 2544 - color: var(--link-hover-color); 2545 - transform: translateY(-2px); 2546 - } 2547 - 2548 - .social-icons .bluesky-icon, 2549 - .social-icons .github-icon, 2550 - .social-icons .linkedin-icon { 2551 - width: 1.4rem; 2552 - height: 1.4rem; 2553 - fill: currentColor; 2554 - } 2555 - 2556 - /* Privacy Policy Footer Styles */ 2557 - .privacy-footer { 2558 - background: var(--nav-bg); 2559 - border-top: var(--nav-border); 2560 - margin-top: 3rem; 2561 - padding: 2rem 0; 2562 - } 2563 - 2564 - .footer-content { 2565 - display: flex; 2566 - justify-content: center; 2567 - align-items: center; 2568 - flex-wrap: wrap; 2569 - gap: 1.5rem; 2570 - } 2571 - 2572 - .footer-social { 2573 - display: flex; 2574 - gap: 1rem; 2575 - align-items: center; 2576 - } 2577 - 2578 - .footer-social a { 2579 - display: flex; 2580 - align-items: center; 2581 - justify-content: center; 2582 - width: 2.5rem; 2583 - height: 2.5rem; 2584 - border-radius: 50%; 2585 - background: transparent; 2586 - color: var(--text-color); 2587 - text-decoration: none; 2588 - transition: all 0.2s ease; 2589 - border: none; 2590 - } 2591 - 2592 - .footer-social a:hover, 2593 - .footer-social a:focus { 2594 - background: transparent; 2595 - color: var(--link-hover-color); 2596 - transform: translateY(-2px); 2597 - } 2598 - 2599 - .footer-social .bluesky-icon, 2600 - .footer-social .github-icon, 2601 - .footer-social .linkedin-icon { 2602 - width: 1.2rem; 2603 - height: 1.2rem; 2604 - fill: currentColor; 2605 - } 2606 - 2607 - 2608 - /* Mobile responsive social icons */ 2609 - @media (max-width: 650px) { 2610 - .social-icons { 2611 - margin: 1.5rem 0; 2612 - padding: 0.5rem 0; 2613 - gap: 1rem; 2614 - } 2615 - 2616 - .social-icons a { 2617 - width: 3.5rem; 2618 - height: 3.5rem; 2619 - /* Ensure minimum touch target size on mobile */ 2620 - min-width: 48px; 2621 - min-height: 48px; 2622 - } 2623 - 2624 - .social-icons .bluesky-icon, 2625 - .social-icons .github-icon, 2626 - .social-icons .linkedin-icon { 2627 - width: 1.6rem; 2628 - height: 1.6rem; 2629 - } 2630 - } 2631 - 2632 - /* Mobile responsive footer */ 2633 - @media (max-width: 650px) { 2634 - .privacy-footer { 2635 - padding: 1.5rem 0; 2636 - } 2637 - 2638 - .footer-content { 2639 - flex-direction: column; 2640 - gap: 1rem; 2641 - text-align: center; 2642 - } 2643 - 2644 - .footer-social { 2645 - justify-content: center; 2646 - } 2647 - }