Portfolio Code with Explanations

<!DOCTYPE html>
Declares the document as HTML5, ensuring browsers use the correct rendering mode.
<html lang="en" >
Opens the root <html> element and sets the document language to English (lang="en").
<head>
<head> section begins—this will contain metadata, links, and the page title.
<meta charset="UTF-8" />
<meta charset="UTF-8" /> specifies UTF-8 character encoding, supporting most international characters.
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="viewport"> makes the page responsive on mobile devices by setting the viewport width to the device's width and initial scale to 1.
<title>DackDev - Portfolio</title>
Sets the text shown in the browser tab to “DackDev - Portfolio.”
Blank line for readability (no effect on rendering).
<link
<link> tag begins loading an external stylesheet (Devicon icons).
rel="stylesheet"
rel="stylesheet" tells the browser that this link is a CSS file.
href="https://cdn.jsdelivr.net/gh/devicons/devicon@latest/devicon.min.css"
Points to the Devicon CSS file on the jsDelivr CDN so you can use technology icons (HTML, CSS, JS, etc.).
/>
Closes the Devicon CSS <link> tag (self-closing).
<link
<link> tag begins loading another stylesheet (Font Awesome icons).
rel="stylesheet"
rel="stylesheet" again indicates this is a CSS file.
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"
Points to the Font Awesome CSS file on the cdnjs CDN to load icon fonts.
crossorigin="anonymous"
Allows anonymous cross-origin requests for the Font Awesome CSS (recommended for CDN assets).
referrerpolicy="no-referrer"
Instructs the browser not to send referrer information when requesting this resource (extra privacy/security).
/>
Closes the Font Awesome <link> tag (self-closing).
Blank line for readability.
<style>
Opens an embedded CSS block—everything until </style> is custom styling for this page.
:root {
Begins defining CSS custom properties (variables) for colors, fonts, and blur values.
--clr-dark-bg: #121212;
Defines a dark background color variable.
--clr-glass-bg: rgba(20, 20, 20, 0.7);
Defines a semi-transparent background color for implementing a “glassmorphic” look.
--clr-light-red: #ff6f6f;
Defines a light-red accent color variable.
--clr-border-red: rgba(255, 111, 111, 0.4);
Defines a semi-transparent red color variable for borders.
--clr-text-light: #eee;
Defines a light-gray/white color variable for text.
--clr-text-accent: #ff6f6f;
Defines a red color variable to emphasize certain text elements.
--clr-shadow-red: rgba(255, 111, 111, 0.35);
Defines a semi-transparent red color variable for drop shadows and glows.
--glass-blur: 18px;
Defines the blur radius (18px) used in backdrop-filter for the glass effect.
--font-mono: 'Fira Code', monospace;
Defines a monospace font stack variable (Fira Code) for consistent code appearance.
}
Closes the :root block containing CSS variables.
Blank line for readability in CSS.
@import url('https://fonts.googleapis.com/css2?family=Fira+Code&display=swap');
Imports the “Fira Code” font from Google Fonts so it can be used in this page.
Blank line for readability.
*, *::before, *::after {
Universal selector that applies to all elements and their ::before/::after pseudo-elements—it resets margins/padding and sets box-sizing.
margin: 0; padding: 0; box-sizing: border-box;
Resets default margins and paddings to zero, and makes every element use border-box sizing for consistent box calculations.
}
Closes the universal selector block.
Blank line for readability.
body {
Begins styling for the body element (the entire visible page).
background: var(--clr-dark-bg);
Sets the page background color to dark (#121212).
color: var(--clr-text-light);
Sets the default text color to light-gray (#eee).
font-family: var(--font-mono);
Applies the Fira Code monospace font to all text in the body.
min-height: 100vh;
Ensures the body occupies at least the full viewport height.
display: flex;
Makes the body a flex container, allowing easy centering or layout of child elements if needed.
justify-content: center;
Centers children horizontally within the body container.
align-items: center;
Centers children vertically within the body container.
padding: 2rem;
Adds 2rem of padding around the entire page content.
user-select: none;
Prevents text selection by default (to avoid accidental highlights).
position: relative;
Sets position: relative on the body so child elements (like pseudo-elements) can position relative to it.
overflow-x: hidden;
Hides any horizontal scrollbar or overflow that might appear unexpectedly.
}
Closes the body styling block.
Blank line for readability.
body::before {
body::before is a pseudo-element that will render a large decorative “</>” behind all content.
content: '</>';
Sets the pseudo-element’s text content to “</>”.
position: fixed;
Fixes the pseudo-element relative to the viewport (it won’t scroll away).
top: 15%;
Positions it 15% down from the top of the viewport.
left: 10%;
Positions it 10% from the left side of the viewport.
font-size: 12rem;
Makes the pseudo-element’s font size very large (12rem) for a subtle background watermark effect.
color: rgba(255 111 111 / 0.06);
Colors it a very transparent red (6% opacity), so it remains in the background without interfering with readability.
font-weight: 900;
Makes the pseudo-element’s text very bold (heavy weight).
font-family: var(--font-mono);
Ensures it uses the same monospace font (Fira Code) for consistency.
user-select: none;
Prevents selecting this decorative text with the cursor.
pointer-events: none;
Disables mouse interactions on this pseudo-element, so clicks pass through to real content below.
transform: rotate(-15deg);
Rotates the “</>” by –15 degrees for a stylized, slanted appearance.
z-index: 0;
Places this element behind all other content (since main content uses z-index: 1 later on).
}
Closes the body::before styling block.
Blank line for readability.
main {
Begins styling for the <main> element, which will be your glassmorphic portfolio card container.
background: var(--clr-glass-bg);
Applies the semi-transparent “glass” background color to the <main> container.
border-radius: 16px;
Rounds the corners of <main> by 16px for a smooth look.
border: 1.5px solid var(--clr-border-red);
Adds a thin red border (1.5px) around the <main> container.
box-shadow:
Begins specifying drop shadows and an inset glow effect around <main>.
0 8px 24px var(--clr-shadow-red),
Creates a red-tinted drop shadow offset 8px down with 24px blur.
inset 0 0 40px rgba(255 111 111 / 0.15);
Adds a subtle red glow inside the container (inset) with 40px blur at 15% opacity.
backdrop-filter: blur(var(--glass-blur));
Applies a blur of 18px behind the semi-transparent background, creating a frosted-glass effect.
-webkit-backdrop-filter: blur(var(--glass-blur));
Safari/WebKit-specific property to ensure the same blur effect on compatible browsers.
width: 100%;
Makes <main> span 100% of its parent container’s width (constrained by max-width).
max-width: 460px;
Caps <main> at 460px wide so it never becomes too wide on large screens.
padding: 2.6rem 2rem 3rem;
Adds top/bottom padding inside <main>: 2.6rem top, 3rem bottom, and 2rem on left/right.
text-align: center;
Centers all text and inline content horizontally inside <main>.
user-select: text;
Allows selecting text within <main> (overrides the body’s no-select).
position: relative;
Positions <main> relative to allow layering with z-index.
z-index: 1;
Places <main> above the decorative body::before pseudo-element (which was z-index: 0).
}
Closes the <main> styling block.
Blank line for readability.
h1 {
Begins styling for the main heading (<h1>) “DackDev.”
font-size: 2.5rem;
Sets the heading’s font size to 2.5rem for prominence.
font-weight: 900;
Makes the heading very bold for emphasis.
margin-bottom: 1rem;
Adds 1rem of space below the heading.
color: var(--clr-light-red);
Colors the heading text in light-red (#ff6f6f).
text-shadow: 0 0 12px var(--clr-light-red);
Adds a subtle red glow around the heading text.
user-select: text;
Allows the heading text to be selected.
opacity: 0;
Starts the heading invisible so it can fade in via animation.
transform: translateY(-10px);
Moves the heading up by 10px initially, for a “fadeInUp” effect when animating.
animation: fadeInUp 0.7s forwards 0.3s;
Applies the fadeInUp keyframe (described later) over 0.7s, starting 0.3s after page load, and retains final state.
}
Closes the h1 styling block.
Blank line for readability.
img.profile {
Begins styling for the <img class="profile"> profile picture.
width: 140px;
Fixes the image’s displayed width to 140px.
height: 140px;
Fixes the image’s displayed height to 140px (making it square).
border-radius: 50%;
Rounds the image into a perfect circle by giving it 50% border radius.
border: 3px solid var(--clr-light-red);
Adds a solid 3px red border around the circular image.
box-shadow: 0 0 18px var(--clr-light-red);
Gives the image a red glow shadow (18px blur).
object-fit: cover;
Ensures the image covers its 140×140 area proportionally (cropping if needed) so it doesn’t distort.
margin: 1.8rem auto 2rem;
Centers the image horizontally (auto left/right) with 1.8rem top margin and 2rem bottom margin.
cursor: default;
Keeps the default arrow cursor when hovering over the image—no hand pointer.
transition: transform 0.35s ease, box-shadow 0.35s ease;
Animates any transform or shadow changes over 0.35 seconds for a smooth hover effect.
opacity: 0;
Starts the image invisible so it can fade in via the fadeInScale animation.
transform: scale(0.9);
Scales the image down to 90% of its normal size initially (for scale-in animation).
animation: fadeInScale 0.7s forwards 0.6s;
Runs the fadeInScale keyframe (described later) over 0.7s, starting 0.6s after page load, then holds final state.
}
Closes the img.profile styling block.
img.profile:hover {
Begins hover styling for the profile image.
transform: scale(1.06) rotate(1.2deg);
On hover, slightly scales the image up to 106% and rotates it by 1.2 degrees for a subtle “pop” effect.
box-shadow: 0 0 28px var(--clr-light-red);
Intensifies the red glow shadow to 28px blur while hovering.
}
Closes the img.profile:hover styling block.
Blank line for readability.
p.description {
Begins styling for the paragraph with class=“description” (short bio under the image).
font-size: 1rem;
Sets normal text size (1rem, roughly 16px base).
line-height: 1.5;
Increases line spacing to 1.5 for better readability.
max-width: 380px;
Limits paragraph width to 380px so lines don’t get too long.
margin-left: auto;
Centers the paragraph horizontally by auto left margin.
margin-right: auto;
Centers the paragraph horizontally by auto right margin.
letter-spacing: 0.03em;
Adds a slight letter spacing (0.03em) for improved readability.
color: var(--clr-text-light);
Sets paragraph text color to light-gray (#eee).
user-select: text;
Allows selecting the paragraph text (overrides body’s no-select).
opacity: 0;
Starts paragraph invisible so it can fade in via animation.
transform: translateY(10px);
Moves the paragraph down 10px initially (for fadeInUp effect).
animation: fadeInUp 0.7s forwards 0.9s;
Applies fadeInUp over 0.7s, starting 0.9s after load, then holds final state.
}
Closes the p.description styling block.
Blank line for readability.
.skills {
Begins styling for the container class=“skills” that holds all individual skill blocks.
margin-top: 2.8rem;
Adds 2.8rem of space above the skills section.
display: flex;
Makes the skills container a flex container to arrange skill items in a row.
justify-content: space-around;
Spaces skill items evenly across the row.
gap: 1.6rem;
Adds 1.6rem of space between each skill item.
flex-wrap: wrap;
Allows skill items to wrap onto a new line if the container is too narrow.
user-select: none;
Prevents selecting skill icons or text accidentally as the page loads.
opacity: 0;
Starts the skills container invisible so it can fade in with the animation.
animation: fadeInUp 0.7s forwards 1.2s;
Applies fadeInUp over 0.7s, starting 1.2s after load, then holds final state.
}
Closes the .skills styling block.
Blank line for readability.
.skill {
Begins styling for each individual skill block (class=“skill”).
width: 100px;
Fixes each skill item’s width to 100px.
display: flex;
Makes each skill item a flex container.
flex-direction: column;
Stacks icon, progress bar container, and percent text vertically.
align-items: center;
Centers children horizontally in each skill block.
gap: 0.6rem;
Adds 0.6rem of vertical spacing between elements inside each skill block.
color: var(--clr-text-light);
Sets the default text/icon color to light-gray (#eee). For the percent text, it will be overridden later.
font-size: 0.85rem;
Sets a slightly smaller font size for percent text (0.85rem).
text-shadow: 0 0 6px rgba(0,0,0,0.7);
Adds a subtle dark drop shadow behind the text for contrast.
}
Closes the .skill styling block.
Blank line for readability.
.skill i {
Begins styling for the <i> icon inside each .skill (Devicon icon).
font-size: 3.8rem;
Sets the icon size to 3.8rem (large).
color: var(--clr-light-red);
Colors the icon in light-red (#ff6f6f).
text-shadow: 0 0 12px var(--clr-light-red);
Adds a red glow around the icon for emphasis.
user-select: none;
Prevents selecting the icon with the cursor.
}
Closes the .skill i styling block.
Blank line for readability.
.skill .percent {
Begins styling for the .percent text inside each skill block.
font-weight: 700;
Makes the percent text bold.
letter-spacing: 0.05em;
Adds slight letter spacing to the percent text for clarity.
color: var(--clr-text-accent);
Overrides text color to accent red (#ff6f6f) for percent numbers.
}
Closes the .skill .percent styling block.
Blank line for readability.
.progressbar-container {
Begins styling for the progress bar container inside each skill block.
width: 90px;
Fixes the container’s width to 90px.
height: 12px;
Fixes the container’s height to 12px.
margin-top: 0.25rem;
Adds a small gap (0.25rem) above the container, separating it from the icon.
}
Closes the .progressbar-container styling block.
Blank line for readability.
.social-links {
Begins styling for the container of social media icon links at the bottom of <main>.
margin-top: 2rem;
Adds 2rem of space above the social links section.
display: flex;
Makes the social links container a flexbox to arrange icons horizontally.
justify-content: center;
Centers social icons horizontally within the container.
gap: 1.3rem;
Adds 1.3rem of space between each social icon link.
opacity: 0;
Starts the container invisible so it can fade in later via animation.
animation: fadeInUp 0.7s forwards 1.5s;
Applies the fadeInUp keyframe over 0.7s, beginning at 1.5s after page load, then holds final state.
}
Closes the .social-links styling block.
Blank line for readability.
.social-links a {
Begins styling for each anchor (<a>) inside .social-links, which are the icons.
color: var(--clr-light-red);
Sets social icon color to light-red (#ff6f6f).
font-size: 1.8rem;
Makes each social icon 1.8rem in size.
text-shadow: 0 0 12px var(--clr-light-red);
Adds a red glow behind the icons for emphasis.
transition: color 0.3s ease, transform 0.3s ease;
Animates color and scale changes on hover/focus over 0.3 seconds for a smooth effect.
}
Closes the .social-links a initial styling block.
.social-links a:hover,
Begins hover and focus-visible styling for social icon links (both mouse hover and keyboard focus).
.social-links a:focus-visible {
Continues the same rule for when an icon link receives keyboard focus (for accessibility).
color: #ff4f4f;
Darkens the red color slightly on hover/focus to give feedback to the user.
transform: scale(1.2);
Scales the icon up by 20% to visually indicate hover or focus.
outline: none;
Removes the default focus outline, since we’re providing a custom hover/focus style (color + scale).
}
Closes the hover/focus-visible styling block.
Blank line for readability.
@media (max-width: 400px) {
Begins a media query targeting screens 400px wide or narrower (very small mobile).
main {
Inside this media query, adjusts the <main> container for small screens.
max-width: 90vw;
Sets <main> max width to 90% of viewport width, so it fits nicely on tiny screens.
padding: 2rem 1.5rem 2.5rem;
Reduces padding inside <main> to 2rem top, 2.5rem bottom, 1.5rem sides for mobile.
}
Closes main adjustments in the media query.
.skill {
Begins adjustments for each .skill block on small screens.
width: 80px;
Reduces each skill block’s width to 80px so they fit better on a small screen.
font-size: 0.8rem;
Reduces the font size of percent text to 0.8rem for readability on mobile.
}
Closes .skill adjustments.
.skill i {
Begins adjustments for <i> icons inside .skill blocks on small screens.
font-size: 3rem;
Reduces icon size to 3rem for better fit on mobile.
}
Closes .skill i adjustments.
.progressbar-container {
Begins adjustments for .progressbar-container on small screens.
width: 75px;
Reduces progress bar container width to 75px for mobile.
height: 10px;
Reduces progress bar height to 10px for a more compact look.
}
Closes .progressbar-container adjustments.
h1 {
Begins adjustments for <h1> on mobile.
font-size: 2rem;
Reduces heading size to 2rem on small screens.
}
Closes h1 adjustments.
img.profile {
Begins adjustments for the profile image on mobile.
width: 110px;
Reduces image width to 110px on small screens.
height: 110px;
Reduces image height to 110px for consistency.
margin-bottom: 1.4rem;
Reduces bottom margin below the image to 1.4rem for tighter spacing.
}
Closes img.profile adjustments.
.social-links a {
Begins adjustments for social icons on small screens.
font-size: 1.5rem;
Reduces social icon size to 1.5rem for mobile.
}
Closes .social-links a adjustments.
.loader {
Begins adjustments for the loading spinner on mobile.
width: 60px;
Reduces the spinner container width to 60px.
height: 60px;
Reduces the spinner container height to 60px.
}
Closes .loader adjustments.
.ring1 {
Begins adjustments for the first ring of the spinner on mobile.
width: 60px;
Reduces ring1 diameter to 60px.
height: 60px;
Reduces ring1 diameter to 60px.
}
Closes .ring1 adjustments.
.ring2 {
Begins adjustments for the second ring of the spinner on mobile.
width: 45px;
Reduces ring2 diameter to 45px.
height: 45px;
Reduces ring2 diameter to 45px.
top: 7.5px;
Repositions ring2 7.5px from the top inside the spinner container.
left: 7.5px;
Repositions ring2 7.5px from the left inside the spinner container.
}
Closes .ring2 adjustments.
.ring3 {
Begins adjustments for the third ring of the spinner on mobile.
width: 30px;
Reduces ring3 diameter to 30px.
height: 30px;
Reduces ring3 diameter to 30px.
top: 15px;
Repositions ring3 15px from the top inside the spinner container.
left: 15px;
Repositions ring3 15px from the left inside the spinner container.
}
Closes .ring3 adjustments.
.ring4 {
Begins adjustments for the fourth ring of the spinner on mobile.
width: 15px;
Reduces ring4 diameter to 15px.
height: 15px;
Reduces ring4 diameter to 15px.
top: 22.5px;
Repositions ring4 22.5px from the top inside the spinner container.
left: 22.5px;
Repositions ring4 22.5px from the left inside the spinner container.
}
Closes .ring4 adjustments.
}
Closes the @media (max-width: 400px) block, finishing mobile-specific adjustments.
Blank line for readability.
@keyframes fadeInUp {
Defines the “fadeInUp” animation keyframes—used to fade an element in while moving it upward.
to {
“to” indicates the final state of the animation (100% progress).
opacity: 1;
Sets the element’s opacity to 1 (fully visible) at the end of the animation.
transform: translateY(0);
Moves the element back to its normal position (Y = 0) at the end of the animation.
}
Closes the to block of the keyframes.
}
Closes the @keyframes fadeInUp block.
@keyframes fadeInScale {
Defines the “fadeInScale” animation keyframes—used to fade in an element while scaling it up.
to {
“to” indicates the final state of the animation (100% progress).
opacity: 1;
Sets the element’s opacity to 1 at the end of the animation.
transform: scale(1);
Scales the element to its normal size (scale = 1) at the end of the animation.
}
Closes the to block of the fadeInScale keyframes.
}
Closes the @keyframes fadeInScale block.
</style>
Closes the embedded CSS block.
</head>
Closes the <head> section entirely.
<body>
Opens the <body> section, where all visible content will appear.
<div id="loading-screen" aria-label="Loading content" role="alert" aria-busy="true">
Begins a full-screen overlay (with id=“loading-screen”) to display animated rings while the page loads. ARIA attributes indicate it’s a busy “loading” alert.
<div class="loader">
Begins the container for the loading spinner—holds four “ring” elements.
<div class="ring ring1"></div>
First (largest) ring of the spinner, styled to rotate continuously with a CSS animation.
<div class="ring ring2"></div>
Second ring, slightly smaller, spins in the opposite direction for a layered effect.
<div class="ring ring3"></div>
Third ring, smaller still, spinning a bit faster than the first two.
<div class="ring ring4"></div>
Fourth (smallest) ring, spinning fastest and typically in reverse direction for visual interest.
</div>
Closes the .loader container.
</div>
Closes the #loading-screen overlay (will be hidden via JavaScript after page load).
Blank line for readability in HTML.
<main role="main" aria-label="Developer portfolio container">
<main> element begins: this will be the main portfolio card container, labeled for screen readers as a “Developer portfolio container.”
<h1>DackDev</h1>
The main heading that displays “DackDev.”
<img
Begins an <img> tag for the profile picture; multiple attributes follow on new lines.
class="profile"
Assigns the CSS class “profile” so it can be styled in CSS.
src="https://cdn.discordapp.com/avatars/808417465012584468/8ba5ea98bfb37790dd9a63574dd9ab75.png?size=1024"
Specifies the image source URL (a Discord avatar URL) to load as the profile picture.
alt="Beautiful Portrait of Dack"
Provides alternative text “Beautiful Portrait of Dack” for accessibility (screen readers, SEO, or if image fails to load).
width="140" height="140" loading="lazy" draggable="false"
Sets explicit width & height to 140px each (optimizes layout), uses loading="lazy" to defer off-screen image loading, and draggable="false" to disable dragging.
/>
Closes the <img> tag (self-closing).
<p class="description">
Opens a paragraph with class=“description” that will hold a short bio or description text.
I'm a 15-year-old programmer focused on mastering clean, efficient code with a passion for making things work flawlessly.
The actual bio text inside the description paragraph, describing the developer’s age, focus on clean code, and passion.
</p>
Closes the description paragraph.
Blank line for readability in HTML.
<section class="skills" aria-label="Coding skill proficiency">
Opens a <section> with class=“skills” that contains all skill blocks. ARIA label indicates it’s “Coding skill proficiency.”
<div class="skill" data-skill="html" data-level="65">
First skill block for HTML. data-skill="html" identifies the skill name, and data-level="65" indicates proficiency percentage (65%).
<i class="devicon-html5-plain"></i>
Displays an HTML5 icon from Devicon by using the class devicon-html5-plain.
<div class="progressbar-container" id="bar-html"></div>
An empty container (20×12px) where JavaScript will inject a colored <div> representing the HTML skill bar fill.
<div class="percent">65%</div>
Displays the textual “65%” next to the HTML icon to show proficiency.
</div>
Closes the first skill block (<div class="skill" data-skill="html">).
<div class="skill" data-skill="css" data-level="45">
Second skill block for CSS. data-skill="css" name and data-level="45" indicates 45% proficiency.
<i class="devicon-css3-plain"></i>
Displays a CSS3 icon from Devicon.
<div class="progressbar-container" id="bar-css"></div>
Empty container where JS will inject the CSS skill bar fill.
<div class="percent">45%</div>
Displays “45%” for CSS proficiency.
</div>
Closes the CSS skill block.
<div class="skill" data-skill="python" data-level="20">
Third skill block for Python. data-skill="python" indicates skill, and data-level="20" indicates 20% proficiency.
<i class="devicon-python-plain"></i>
Displays a Python icon from Devicon.
<div class="progressbar-container" id="bar-python"></div>
Empty container where JS will inject the Python skill bar fill.
<div class="percent">20%</div>
Displays “20%” for Python proficiency.
</div>
Closes the Python skill block.
<div class="skill" data-skill="js" data-level="10">
Fourth skill block for JavaScript. data-skill="js" indicates skill, and data-level="10" indicates 10% proficiency.
<i class="devicon-javascript-plain"></i>
Displays a JavaScript icon from Devicon.
<div class="progressbar-container" id="bar-js"></div>
Empty container where JS will inject the JS skill bar fill.
<div class="percent">10%</div>
Displays “10%” for JavaScript proficiency.
</div>
Closes the JavaScript skill block.
</section>
Closes the <section class="skills">, ending the skills list.
Blank line for readability.
<nav class="social-links" aria-label="Social media links">
Begins a navigation section (<nav>) for social media icon links. ARIA label indicates “Social media links.”
<a href="https://open.spotify.com/user/31zw8av3b3ksqfwhavv17b76rsua" aria-label="Spotify profile" target="_blank" rel="noopener noreferrer">
An anchor linking to a Spotify profile. target="_blank" opens in a new tab, and rel="noopener noreferrer" improves security.
<i class="fab fa-spotify"></i>
Displays a Spotify icon via Font Awesome (fab fa-spotify).
</a>
Closes the Spotify link anchor.
<a href="https://discord.com/users/808417465012584468" aria-label="Discord profile" target="_blank" rel="noopener noreferrer">
An anchor linking to a Discord profile, with ARIA label “Discord profile.”
<i class="fab fa-discord"></i>
Displays a Discord icon via Font Awesome (fab fa-discord).
</a>
Closes the Discord link anchor.
<a href="https://github.com/NotDack" aria-label="GitHub profile" target="_blank" rel="noopener noreferrer">
An anchor linking to a GitHub profile, labeled “GitHub profile.”
<i class="fab fa-github"></i>
Displays a GitHub icon via Font Awesome (fab fa-github).
</a>
Closes the GitHub link anchor.
</nav>
Closes the navigation section (<nav class="social-links">).
</main>
Closes the main portfolio card container (<main>).
Blank line for readability.
<script>
Opens a JavaScript block—everything until </script> will run in the browser.
document.addEventListener("DOMContentLoaded", () => {
Adds an event listener that waits until the DOM is fully loaded before running the code inside.
const loadingScreen = document.getElementById("loading-screen");
Selects the <div id="loading-screen"> overlay and stores it in a variable for later manipulation.
Blank line for readability in JavaScript.
setTimeout(() => {
Begins a timer that will execute the enclosed code after a specified delay (1 second).
loadingScreen.classList.add("fade-out");
Adds the “fade-out” class to the loading overlay to trigger a CSS transition that hides it.
}, 1000);
Specifies a 1000ms (1 second) delay before hiding the loading overlay.
Blank line for readability in JavaScript.
const skills = document.querySelectorAll(".skill");
Selects all elements with class=“skill” (the four skill blocks) and stores them in a NodeList.
skills.forEach((skill) => {
Loops over each .skill element to build and animate its progress bar.
const level = skill.dataset.level;
Retrieves the numeric percentage (e.g. “65”) from the data-level attribute of the skill element.
const barContainer = skill.querySelector(".progressbar-container");
Finds the empty .progressbar-container inside the current .skill to later insert the fill bar.
const progressBar = document.createElement("div");
Creates a new <div> element which will become the colored fill for the skill bar.
progressBar.style.width = "0%";
Initializes the fill bar’s width at 0% so it can animate from 0 to the actual level.
progressBar.style.height = "8px";
Sets its height to 8px (a little smaller than the container’s 12px to leave a tiny top/bottom margin).
progressBar.style.backgroundColor = "var(--clr-light-red)";
Gives the fill bar a light-red background color (#ff6f6f).
progressBar.style.borderRadius = "6px";
Rounds its corners with 6px border radius so it fits nicely inside the container’s rounded corners.
progressBar.style.boxShadow = "0 0 6px var(--clr-light-red)";
Adds a subtle red glow shadow under the fill bar for depth.
progressBar.style.transition = "width 1.3s ease";
Animates the fill bar’s width property over 1.3 seconds with easing.
barContainer.appendChild(progressBar);
Inserts the newly created fill bar into the empty .progressbar-container.
setTimeout(() => {
Begins another timer to delay the width change, so the fill animation starts after the overlay hides.
progressBar.style.width = `${level}%`;
After the delay, sets the fill bar’s width to the actual percentage (e.g. “65%”), animating it from 0% → 65%.
}, 1400);
Specifies a 1400ms (1.4s) delay before animating the bar width.
});
Closes the skills.forEach(…) loop.
});
Closes the DOMContentLoaded event listener callback.
</script>
Closes the JavaScript block.
</body>
Closes the <body> section of the HTML document.
</html>
Closes the <html> element, ending the entire HTML document.