diff --git a/assets/back-to-home.svg b/assets/back-to-home.svg new file mode 100644 index 0000000..d1f9126 --- /dev/null +++ b/assets/back-to-home.svg @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/assets/chevron_left.svg b/assets/chevron_left.svg new file mode 100644 index 0000000..39c498b --- /dev/null +++ b/assets/chevron_left.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/chevron_right.svg b/assets/chevron_right.svg new file mode 100644 index 0000000..0e27809 --- /dev/null +++ b/assets/chevron_right.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/cross.svg b/assets/cross.svg new file mode 100644 index 0000000..53b50a1 --- /dev/null +++ b/assets/cross.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/height.svg b/assets/height.svg new file mode 100644 index 0000000..e5a0bbc --- /dev/null +++ b/assets/height.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/assets/pokeball.ico b/assets/pokeball.ico new file mode 100644 index 0000000..e258f39 Binary files /dev/null and b/assets/pokeball.ico differ diff --git a/assets/pokeball.svg b/assets/pokeball.svg new file mode 100644 index 0000000..99c3555 --- /dev/null +++ b/assets/pokeball.svg @@ -0,0 +1,18 @@ + + + + \ No newline at end of file diff --git a/assets/pokedex.svg b/assets/pokedex.svg new file mode 100644 index 0000000..62539f8 --- /dev/null +++ b/assets/pokedex.svg @@ -0,0 +1,4 @@ + + + + diff --git a/assets/search.svg b/assets/search.svg new file mode 100644 index 0000000..69fc7a7 --- /dev/null +++ b/assets/search.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/sorting.svg b/assets/sorting.svg new file mode 100644 index 0000000..685553c --- /dev/null +++ b/assets/sorting.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/weight.svg b/assets/weight.svg new file mode 100644 index 0000000..a58c0e9 --- /dev/null +++ b/assets/weight.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/detail.html b/detail.html new file mode 100644 index 0000000..58398f2 --- /dev/null +++ b/detail.html @@ -0,0 +1,97 @@ + + + + + + Pokemon Detail + + + + +
+
+
+
+ + back to home + +
+

+
+
+
+

+
+
+
+ +
+
+

+

+
+

About

+
+
+
+ weight +

+
+

Weight

+
+
+
+ height +

+
+

Height

+
+
+
+

Move

+
+
+

+

Base Stats

+
+
+

HP

+

+ +
+
+

ATK

+

+ +
+
+

DEF

+

+ +
+
+

SATK

+

+ +
+
+
+ pokedex +
+ + diff --git a/index.html b/index.html new file mode 100644 index 0000000..bc5759a --- /dev/null +++ b/index.html @@ -0,0 +1,62 @@ + + + + + + + Pokedex + + + + + + + +
+
+
+
+ pokeball +

Pokedex

+
+
+
+ search icon + + cross icon +
+
+
+ sorting +
+
+

Sort by:

+
+
+ + +
+
+ + +
+
+
+
+
+
+
+
+
+
+
+
Pokemon not found
+
+ + +
+ + + \ No newline at end of file diff --git a/pokemon-detail.js b/pokemon-detail.js new file mode 100644 index 0000000..bc1e5f6 --- /dev/null +++ b/pokemon-detail.js @@ -0,0 +1,253 @@ +let currentPokemonId = null; + +document.addEventListener("DOMContentLoaded", () => { + const MAX_POKEMONS = 350; + const pokemonID = new URLSearchParams(window.location.search).get("id"); + const id = parseInt(pokemonID, 10); + + if (id < 1 || id > MAX_POKEMONS) { + return (window.location.href = "./index.html"); + } + + currentPokemonId = id; + loadPokemon(id); +}); + +async function loadPokemon(id) { + try { + const [pokemon, pokemonSpecies] = await Promise.all([ + fetch(`https://pokeapi.co/api/v2/pokemon/${id}`).then((res) => + res.json() + ), + fetch(`https://pokeapi.co/api/v2/pokemon-species/${id}`).then((res) => + res.json() + ), + ]); + + const abilitiesWrapper = document.querySelector( + ".pokemon-detail-wrap .pokemon-detail.move" + ); + abilitiesWrapper.innerHTML = ""; + + if (currentPokemonId === id) { + displayPokemonDetails(pokemon); + const flavorText = getEnglishFlavorText(pokemonSpecies); + document.querySelector(".body3-fonts.pokemon-description").textContent = + flavorText; + + const [leftArrow, rightArrow] = ["#leftArrow", "#rightArrow"].map((sel) => + document.querySelector(sel) + ); + leftArrow.removeEventListener("click", navigatePokemon); + rightArrow.removeEventListener("click", navigatePokemon); + + if (id !== 1) { + leftArrow.addEventListener("click", () => { + navigatePokemon(id - 1); + }); + } + if (id !== 151) { + rightArrow.addEventListener("click", () => { + navigatePokemon(id + 1); + }); + } + + window.history.pushState({}, "", `./detail.html?id=${id}`); + } + + return true; + } catch (error) { + console.error("An error occured while fetching Pokemon data:", error); + return false; + } +} + +async function navigatePokemon(id) { + currentPokemonId = id; + await loadPokemon(id); +} + +const typeColors = { + normal: "#A8A878", + fire: "#F08030", + water: "#6890F0", + electric: "#F8D030", + grass: "#78C850", + ice: "#98D8D8", + fighting: "#C03028", + poison: "#A040A0", + ground: "#E0C068", + flying: "#A890F0", + psychic: "#F85888", + bug: "#A8B820", + rock: "#B8A038", + ghost: "#705898", + dragon: "#7038F8", + dark: "#705848", + steel: "#B8B8D0", + dark: "#EE99AC", +}; + +function setElementStyles(elements, cssProperty, value) { + elements.forEach((element) => { + element.style[cssProperty] = value; + }); +} + +function rgbaFromHex(hexColor) { + return [ + parseInt(hexColor.slice(1, 3), 16), + parseInt(hexColor.slice(3, 5), 16), + parseInt(hexColor.slice(5, 7), 16), + ].join(", "); +} + +function setTypeBackgroundColor(pokemon) { + const mainType = pokemon.types[0].type.name; + const color = typeColors[mainType]; + + if (!color) { + console.warn(`Color not defined for type: ${mainType}`); + return; + } + + const detailMainElement = document.querySelector(".detail-main"); + setElementStyles([detailMainElement], "backgroundColor", color); + setElementStyles([detailMainElement], "borderColor", color); + + setElementStyles( + document.querySelectorAll(".power-wrapper > p"), + "backgroundColor", + color + ); + + setElementStyles( + document.querySelectorAll(".stats-wrap p.stats"), + "color", + color + ); + + setElementStyles( + document.querySelectorAll(".stats-wrap .progress-bar"), + "color", + color + ); + + const rgbaColor = rgbaFromHex(color); + const styleTag = document.createElement("style"); + styleTag.innerHTML = ` + .stats-wrap .progress-bar::-webkit-progress-bar { + background-color: rgba(${rgbaColor}, 0.5); + } + .stats-wrap .progress-bar::-webkit-progress-value { + background-color: ${color}; + } + `; + document.head.appendChild(styleTag); +} + +function capitalizeFirstLetter(string) { + return string.charAt(0).toUpperCase() + string.slice(1).toLowerCase(); +} + +function createAndAppendElement(parent, tag, options = {}) { + const element = document.createElement(tag); + Object.keys(options).forEach((key) => { + element[key] = options[key]; + }); + parent.appendChild(element); + return element; +} + +function displayPokemonDetails(pokemon) { + const { name, id, types, weight, height, abilities, stats } = pokemon; + const capitalizePokemonName = capitalizeFirstLetter(name); + + document.querySelector("title").textContent = capitalizePokemonName; + + const detailMainElement = document.querySelector(".detail-main"); + detailMainElement.classList.add(name.toLowerCase()); + + document.querySelector(".name-wrap .name").textContent = + capitalizePokemonName; + + document.querySelector( + ".pokemon-id-wrap .body2-fonts" + ).textContent = `#${String(id).padStart(3, "0")}`; + + const imageElement = document.querySelector(".detail-img-wrapper img"); + imageElement.src = `https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/other/dream-world/${id}.svg`; + imageElement.alt = name; + + const typeWrapper = document.querySelector(".power-wrapper"); + typeWrapper.innerHTML = ""; + types.forEach(({ type }) => { + createAndAppendElement(typeWrapper, "p", { + className: `body3-fonts type ${type.name}`, + textContent: type.name, + }); + }); + + document.querySelector( + ".pokemon-detail-wrap .pokemon-detail p.body3-fonts.weight" + ).textContent = `${weight / 10}kg`; + document.querySelector( + ".pokemon-detail-wrap .pokemon-detail p.body3-fonts.height" + ).textContent = `${height / 10}m`; + + const abilitiesWrapper = document.querySelector( + ".pokemon-detail-wrap .pokemon-detail.move" + ); + abilities.forEach(({ ability }) => { + createAndAppendElement(abilitiesWrapper, "p", { + className: "body3-fonts", + textContent: ability.name, + }); + }); + + const statsWrapper = document.querySelector(".stats-wrapper"); + statsWrapper.innerHTML = ""; + + const statNameMapping = { + hp: "HP", + attack: "ATK", + defense: "DEF", + "special-attack": "SATK", + "special-defense": "SDEF", + speed: "SPD", + }; + + stats.forEach(({ stat, base_stat }) => { + const statDiv = document.createElement("div"); + statDiv.className = "stats-wrap"; + statsWrapper.appendChild(statDiv); + + createAndAppendElement(statDiv, "p", { + className: "body3-fonts stats", + textContent: statNameMapping[stat.name], + }); + + createAndAppendElement(statDiv, "p", { + className: "body3-fonts", + textContent: String(base_stat).padStart(3, "0"), + }); + + createAndAppendElement(statDiv, "progress", { + className: "progress-bar", + value: base_stat, + max: 100, + }); + }); + + setTypeBackgroundColor(pokemon); +} + +function getEnglishFlavorText(pokemonSpecies) { + for (let entry of pokemonSpecies.flavor_text_entries) { + if (entry.language.name === "en") { + let flavor = entry.flavor_text.replace(/\f/g, " "); + return flavor; + } + } + return ""; +} diff --git a/pokemon.js b/pokemon.js new file mode 100644 index 0000000..dc93f67 --- /dev/null +++ b/pokemon.js @@ -0,0 +1,98 @@ +const MAX_POKEMON = 350; +const listWrapper = document.querySelector(".list-wrapper"); +const searchInput = document.querySelector("#search-input"); +const numberFilter = document.querySelector("#number"); +const nameFilter = document.querySelector("#name"); +const notFoundMessage = document.querySelector("#not-found-message"); + +let allPokemons = []; + +fetch(`https://pokeapi.co/api/v2/pokemon?limit=${MAX_POKEMON}`) + .then((response) => response.json()) + .then((data) => { + allPokemons = data.results; + displayPokemons(allPokemons); + }); + +async function fetchPokemonDataBeforeRedirect(id) { + try { + const [pokemon, pokemonSpecies] = await Promise.all([ + fetch(`https://pokeapi.co/api/v2/pokemon/${id}`).then((res) => + res.json() + ), + fetch(`https://pokeapi.co/api/v2/pokemon-species/${id}`).then((res) => + res.json() + ), + ]); + return true; + } catch (error) { + console.error("Failed to fetch Pokemon data before redirect"); + } +} + +function displayPokemons(pokemon) { + listWrapper.innerHTML = ""; + + pokemon.forEach((pokemon) => { + const pokemonID = pokemon.url.split("/")[6]; + const listItem = document.createElement("div"); + listItem.className = "list-item"; + listItem.innerHTML = ` +
+

#${pokemonID}

+
+
+ ${pokemon.name} +
+
+

${pokemon.name}

+
+ `; + + listItem.addEventListener("click", async () => { + const success = await fetchPokemonDataBeforeRedirect(pokemonID); + if (success) { + window.location.href = `./detail.html?id=${pokemonID}`; + } + }); + + listWrapper.appendChild(listItem); + }); +} + +searchInput.addEventListener("keyup", handleSearch); + +function handleSearch() { + const searchTerm = searchInput.value.toLowerCase(); + let filteredPokemons; + + if (numberFilter.checked) { + filteredPokemons = allPokemons.filter((pokemon) => { + const pokemonID = pokemon.url.split("/")[6]; + return pokemonID.startsWith(searchTerm); + }); + } else if (nameFilter.checked) { + filteredPokemons = allPokemons.filter((pokemon) => { + return pokemon.name.toLowerCase().startsWith(searchTerm) + }); + } else { + filteredPokemons = allPokemons; + } + + displayPokemons(filteredPokemons); + + if (filteredPokemons.length === 0) { + notFoundMessage.style.display = "block"; + } else { + notFoundMessage.style.display = "none"; + } +} + +const closeButton = document.querySelector(".search-close-icon"); +closeButton.addEventListener("click", clearSearch); + +function clearSearch() { + searchInput.value = ""; + displayPokemons(allPokemons); + notFoundMessage.style.display = "none"; +} diff --git a/search.js b/search.js new file mode 100644 index 0000000..467e966 --- /dev/null +++ b/search.js @@ -0,0 +1,37 @@ +const inputElement = document.querySelector("#search-input"); +const search_icon = document.querySelector("#search-close-icon"); +const sort_wrapper = document.querySelector(".sort-wrapper"); + +inputElement.addEventListener("input", () => { + handleInputChange(inputElement); +}); +search_icon.addEventListener("click", handleSearchCloseOnClick); +sort_wrapper.addEventListener("click", handleSortIconOnClick); + +function handleInputChange(inputElement) { + const inputValue = inputElement.value; + + if (inputValue !== "") { + document + .querySelector("#search-close-icon") + .classList.add("search-close-icon-visible"); + } else { + document + .querySelector("#search-close-icon") + .classList.remove("search-close-icon-visible"); + } +} + +function handleSearchCloseOnClick() { + document.querySelector("#search-input").value = ""; + document + .querySelector("#search-close-icon") + .classList.remove("search-close-icon-visible"); +} + +function handleSortIconOnClick() { + document + .querySelector(".filter-wrapper") + .classList.toggle("filter-wrapper-open"); + document.querySelector("body").classList.toggle("filter-wrapper-overlay"); +} diff --git a/style.css b/style.css new file mode 100644 index 0000000..3041c84 --- /dev/null +++ b/style.css @@ -0,0 +1,552 @@ +:root { + --identity-primary: #dc0a2d; + + --grayscale-dark: #212121; + --grayscale-medium: #666666; + --grayscale-light: #e0e0e0; + --grayscale-background: #efefef; + --grayscale-white: #ffffff; + + --headline-font-size: 24px; + --body1-font-size: 14px; + --body2-font-size: 12px; + --body3-font-size: 10px; + --subtitle1-font-size: 14px; + --subtitle2-font-size: 12px; + --subtitle3-font-size: 10px; + --caption-font-size: 8px; + + --headline-line-height: 32px; + --common-line-height: 16px; + --caption-line-height: 12px; + + --font-weight-regular: 400; + --font-weight-bold: 700; + + --drop-shadow: 0px 1px 3px 1px rgba(0, 0, 0, 0.2); + --drop-shadow-hover: 0px 3px 12px 3px rgba(0, 0, 0, 0.2); + --drop-shadow-inner: 0px 1px 3px 1px rgba(0, 0, 0, 0.25) inset; +} + +::-webkit-scrollbar { + display: none; +} + +h2, +h3, +h4, +.body1-fonts, +.body2-fonts, +.body3-fonts { + line-height: var(--common-line-height); +} + +h1 { + font-size: var(--headline-font-size); + line-height: var(--headline-line-height); +} + +h2 { + font-size: var(--subtitle1-font-size); +} + +h3 { + font-size: var(--subtitle2-font-size); +} + +h4 { + font-size: var(--subtitle3-font-size); +} + +.body1-fonts { + font-size: var(--body1-font-size); +} + +.body2-fonts { + font-size: var(--body2-font-size); +} + +.body3-fonts { + font-size: var(--body3-font-size); +} + +.caption-fonts { + font-size: var(--caption-font-size); + line-height: var(--caption-line-height); +} + +input:focus-visible { + outline: 0; +} + +.featured-img a.arrow.hidden { + display: none; +} + +body { + margin: 0; + height: 100vh; + width: 100vw; + overflow: hidden scroll; + box-sizing: border-box; + font-family: "Poppins", sans-serif; +} + +.main { + margin: 0; + padding: 0; + background-color: var(--identity-primary); + height: 98vh; + width: 100vw; + display: flex; + flex-direction: column; + align-items: center; + gap: 1rem; +} + +.header.home { + width: 90%; +} + +.container { + width: 100%; + margin: 0; +} + +.logo-wrapper { + display: flex; + align-items: center; +} + +.logo-wrapper > h1 { + color: var(--grayscale-white); +} + +.logo-wrapper > img { + margin-right: 16px; +} + +.search-wrapper, +.search-wrap { + display: flex; + align-items: center; + width: 100%; + gap: 16px; +} + +.search-wrap { + position: relative; + background-color: var(--grayscale-white); + border-radius: 16px; + box-shadow: var(--drop-shadow-inner); + height: 32px; + gap: 8px; +} + +.search-icon { + margin-left: 16px; +} + +.search-wrap svg path { + fill: var(--identity-primary); +} + +.search-wrap > input { + width: 60%; + border: none; +} + +.sort-wrapper { + position: relative; +} + +.sort-wrap { + background-color: var(--grayscale-white); + border-radius: 100%; + min-width: 2rem; + min-height: 2rem; + box-shadow: var(--drop-shadow-inner); + display: flex; + align-items: center; + justify-content: center; + position: relative; +} + +.search-close-icon { + position: absolute; + right: 1rem; + display: none; + cursor: pointer; +} + +.search-close-icon-visible { + display: block; +} + +.filter-wrapper { + position: absolute; + background: var(--identity-primary); + border: 4px solid var(--identity-primary); + border-top: 0; + border-radius: 12px; + padding: 0px 4px 4px 4px; + right: 0px; + box-shadow: var(--drop-shadow-hover); + min-width: 113px; + top: 40px; + display: none; + z-index: 5000; +} + +.filter-wrapper-open { + display: block; +} + +.filter-wrapper-overlay .main::before { + background-color: rgba(0, 0, 0, 0.4); + width: 100%; + height: 100%; + position: absolute; + left: 0; + right: 0; + top: 0; + bottom: 0; + z-index: 2; +} + +.filter-wrapper > .body2-fonts { + color: var(--grayscale-white); + font-weight: var(--font-weight-bold); + padding: 16px 20px; +} + +.filter-wrap { + background-color: var(--grayscale-white); + box-shadow: var(--drop-shadow-inner); + padding: 16px 20px; + border-radius: 8px; +} + +.filter-wrap > div { + display: flex; + align-items: center; + gap: 8px; + margin-bottom: 16px; +} + +.filter-wrap > div:last-child { + margin-bottom: 0px; +} + +.filter-wrap input { + accent-color: var(--identity-primary); +} + +.pokemon-list { + background-color: var(--grayscale-white); + box-shadow: var(--drop-shadow-inner); + border-radius: 0.75rem; + min-height: calc(85.5% - 1rem); + width: calc(100% - 1rem); + max-height: 100px; + overflow-y: auto; +} + +.list-wrapper { + margin: 1rem 0; + display: flex; + align-items: center; + justify-content: center; + flex-wrap: wrap; + gap: 0.75rem; +} + +.list-item { + border-radius: 8px; + box-shadow: var(--drop-shadow); + background-color: var(--grayscale-white); + width: 8.85rem; + height: 8.85rem; + text-align: center; + text-decoration: none; + cursor: pointer; +} + +.list-item .number-wrap { + min-height: 16px; + text-align: right; + padding: 0 8px; + color: var(--grayscale-medium); +} + +.list-item .name-wrap { + border-radius: 7px; + background-color: var(--grayscale-background); + padding: 24px 8px 4px 8px; + color: var(--grayscale-dark); + margin-top: -18px; +} + +.list-item .img-wrap { + width: 72px; + height: 72px; + margin: auto; +} + +.list-item .img-wrap img { + width: 100%; + height: 100%; +} + +/* detail page */ + +.detail-main .header { + padding: 20px 20px 24px 20px; + position: relative; + z-index: 2; +} + +.detail-main .header-wrapper { + display: flex; + align-items: center; + justify-content: space-between; + column-gap: 15px; +} + +.detail-main .header-wrap { + display: flex; + align-items: center; + column-gap: 8px; +} + +.detail-main .back-btn-wrap { + max-height: 32px; +} + +.detail-main .back-btn-wrap path, +.detail-main .header-wrapper p, +.detail-main .header-wrapper h1 { + fill: var(--grayscale-white); + color: var(--grayscale-white); +} + +.detail-main .pokemon-id-wrap p { + font-weight: var(--font-weight-bold); +} + +.detail-img-wrapper { + width: 200px; + height: 200px; + margin: auto; + position: relative; + z-index: 3; +} + +.detail-img-wrapper img { + width: 100%; + height: 100%; +} + +.detail-card-detail-wrapper { + border-radius: 8px; + background-color: var(--grayscale-white); + box-shadow: var(--drop-shadow-inner); + padding: 56px 20px 20px 20px; + margin-top: -50px; + margin-bottom: 50px; + display: flex; + flex-direction: column; + position: relative; + z-index: 2; +} + +.power-wrapper { + display: flex; + justify-content: center; + align-items: center; + flex-wrap: wrap; + gap: 16px; +} + +.power-wrapper > p { + border-radius: 10px; + padding: 2px 8px; + font-weight: var(--font-weight-bold); + color: var(--grayscale-white); + text-transform: capitalize; + background-color: #74cb48; +} + +.pokemon-detail.move p { + text-transform: capitalize; + word-break: break-all; +} + +.list-item .name-wrap p { + text-transform: capitalize; +} + +.detail-card-detail-wrapper .about-text { + font-weight: var(--font-weight-bold); + text-align: center; +} + +.pokemon-detail-wrapper { + display: flex; + align-items: flex-end; +} + +.pokemon-detail-wrapper .pokemon-detail-wrap { + flex: 1; + text-align: center; + position: relative; +} + +.pokemon-detail-wrap:before { + content: ""; + background-color: var(--grayscale-light); + width: 1px; + height: 100%; + position: absolute; + right: 0; + top: 0; + bottom: 0; + margin: auto; +} + +.pokemon-detail-wrap:last-child::before { + display: none; +} + +.pokemon-detail { + display: flex; + justify-content: center; + align-items: center; + padding: 8px 20px; + gap: 8px; +} + +.pokemon-detail-wrapper { + min-height: 76px; +} + +.pokemon-detail.move { + flex-direction: column; + gap: 0; + align-items: center; + padding: 8px 5px; +} + +.pokemon-detail-wrap > .caption-fonts { + color: var(--grayscale-medium); +} + +.pokemon-detail-wrap .straighten { + transform: rotate(90deg); +} + +.detail-card-detail-wrapper .pokemon-description { + color: var(--grayscale-dark); + text-align: center; +} + +.stats-wrap { + display: flex; + align-items: center; +} + +.stats-wrap p { + color: var(--grayscale-dark); + margin-right: 8px; + min-width: 19px; +} + +.stats-wrap p.stats { + text-align: right; + padding-right: 8px; + min-width: 35px; + border-right: 1px solid var(--grayscale-light); + font-weight: var(--font-weight-bold); +} + +.stats-wrap .progress-bar { + flex: 1; + border-radius: 4px; + height: 4px; +} + +.stats-wrap .progress-bar::-webkit-progress-bar { + border-radius: 4px; +} + +.stats-wrap .progress-bar::-webkit-progress-value { + border-radius: 4px; +} + +.detail-bg { + position: absolute; + z-index: 1; + right: 50px; + top: 8px; + opacity: 0.1; +} + +.detail-bg path { + fill: var(--grayscale-white); +} + +div#not-found-message { + display: none; + position: absolute; + left: 50%; + top: 50%; + transform: translate(-50%, -50%); + font-size: 20px; + font-weight: 600; +} + +.arrow img { + -webkit-filter: brightness(0) grayscale(1) invert(1); + filter: brightness(0) grayscale(1) invert(1); + width: 28px; +} + +.featured-img { + position: relative; +} + +.featured-img a.arrow { + display: inline-block; + position: absolute; + top: 50%; + transform: translateY(-50%); + z-index: 999; +} + +.featured-img a.arrow.left-arrow { + left: -2rem; +} + +.featured-img a.arrow.right-arrow { + right: -2rem; +} + +.detail-main.main { + height: max-content; + border-color: transparent; + background-color: transparent; +} + +.footer { + width: 100vw; + background-color: var(--identity-primary); + color: var(--grayscale-white); + text-align: center; + padding: 10px; + margin-top: -16px; +} + +.footer a { + color: var(--grayscale-white); + text-decoration: none; +} \ No newline at end of file