diff --git a/app/components/EventsList.module.css b/app/components/EventsList.module.css new file mode 100644 index 000000000..237139854 --- /dev/null +++ b/app/components/EventsList.module.css @@ -0,0 +1,8 @@ +.dayHeader { + padding: var(--s-2) var(--s-2) var(--s-1); + font-size: var(--font-2xs); + font-weight: var(--weight-bold); + color: var(--color-text-high); + text-transform: uppercase; + letter-spacing: 0.05em; +} diff --git a/app/components/EventsList.tsx b/app/components/EventsList.tsx new file mode 100644 index 000000000..1e455ce22 --- /dev/null +++ b/app/components/EventsList.tsx @@ -0,0 +1,101 @@ +import { isToday, isTomorrow } from "date-fns"; +import { useTranslation } from "react-i18next"; +import type { SidebarEvent } from "~/features/sidebar/core/sidebar.server"; +import styles from "./EventsList.module.css"; +import { ListLink } from "./SideNav"; + +export function EventsList({ + events, + onClick, +}: { + events: SidebarEvent[]; + onClick?: () => void; +}) { + const { t, i18n } = useTranslation(["front"]); + + if (events.length === 0) { + return ( +
+ {t("front:sideNav.noEvents")} +
+ ); + } + + const getDayKey = (timestamp: number) => { + const date = new Date(timestamp * 1000); + return date.toDateString(); + }; + + const formatDayHeader = (date: Date) => { + if (isToday(date)) { + const rtf = new Intl.RelativeTimeFormat(i18n.language, { + numeric: "auto", + }); + const str = rtf.format(0, "day"); + return str.charAt(0).toUpperCase() + str.slice(1); + } + if (isTomorrow(date)) { + const rtf = new Intl.RelativeTimeFormat(i18n.language, { + numeric: "auto", + }); + const str = rtf.format(1, "day"); + return str.charAt(0).toUpperCase() + str.slice(1); + } + return date.toLocaleDateString(i18n.language, { + weekday: "long", + month: "short", + day: "numeric", + }); + }; + + const formatTime = (date: Date) => { + return date.toLocaleTimeString(i18n.language, { + hour: "numeric", + minute: "2-digit", + }); + }; + + const groupedEvents = events.reduce>( + (acc, event) => { + const key = getDayKey(event.startTime); + if (!acc[key]) { + acc[key] = []; + } + acc[key].push(event); + return acc; + }, + {}, + ); + + const dayKeys = Object.keys(groupedEvents); + + return ( + <> + {dayKeys.map((dayKey) => { + const dayEvents = groupedEvents[dayKey]; + const firstDate = new Date(dayEvents[0].startTime * 1000); + + return ( +
+
{formatDayHeader(firstDate)}
+ {dayEvents.map((event) => ( + + {event.scrimStatus === "booked" + ? t("front:sideNav.scrimVs", { opponent: event.name }) + : event.scrimStatus === "looking" + ? t("front:sideNav.lookingForScrim") + : event.name} + + ))} +
+ ); + })} + + ); +} diff --git a/app/components/GearSelect.tsx b/app/components/GearSelect.tsx index 5b210dbd4..1b1ad6763 100644 --- a/app/components/GearSelect.tsx +++ b/app/components/GearSelect.tsx @@ -55,7 +55,7 @@ export function GearSelect({ > {({ key, items: gear, brandId, idx }) => ( { const sanitized = value.replace(CSS_URL_REGEX, ""); return `style=${sanitized}`; - }); + }) + .replace(/ +$/gm, ""); return ( {icon} - {showNotificationDot ? ( - - - - ) : null} + {showNotificationDot ? : null} {label} @@ -293,7 +291,7 @@ function FriendsPanel({ )) ) : ( -
+
{user ? t("front:sideNav.friends.noFriends") : t("front:sideNav.friends.notLoggedIn")} @@ -305,6 +303,7 @@ function FriendsPanel({ onClick={onClose} > {t("common:actions.viewAll")} + ); @@ -317,91 +316,19 @@ function TourneysPanel({ events: NonNullable["events"]; onClose: () => void; }) { - const { t, i18n } = useTranslation(["front"]); - - const formatDayHeader = (date: Date) => { - if (isToday(date)) { - const rtf = new Intl.RelativeTimeFormat(i18n.language, { - numeric: "auto", - }); - const str = rtf.format(0, "day"); - return str.charAt(0).toUpperCase() + str.slice(1); - } - if (isTomorrow(date)) { - const rtf = new Intl.RelativeTimeFormat(i18n.language, { - numeric: "auto", - }); - const str = rtf.format(1, "day"); - return str.charAt(0).toUpperCase() + str.slice(1); - } - return date.toLocaleDateString(i18n.language, { - weekday: "long", - month: "short", - day: "numeric", - }); - }; - - const formatTime = (date: Date) => { - return date.toLocaleTimeString(i18n.language, { - hour: "numeric", - minute: "2-digit", - }); - }; - - const getDayKey = (timestamp: number) => { - const date = new Date(timestamp * 1000); - return date.toDateString(); - }; - - const groupedEvents = events.reduce>( - (acc, event) => { - const key = getDayKey(event.startTime); - if (!acc[key]) { - acc[key] = []; - } - acc[key].push(event); - return acc; - }, - {}, - ); - - const dayKeys = Object.keys(groupedEvents); + const { t } = useTranslation(["front", "common"]); return ( - {events.length > 0 ? ( - dayKeys.map((dayKey) => { - const dayEvents = groupedEvents[dayKey]; - const firstDate = new Date(dayEvents[0].startTime * 1000); - - return ( -
-
- {formatDayHeader(firstDate)} -
- {dayEvents.map((event) => ( - - {event.scrimStatus === "booked" - ? t("front:sideNav.scrimVs", { opponent: event.name }) - : event.scrimStatus === "looking" - ? t("front:sideNav.lookingForScrim") - : event.name} - - ))} -
- ); - }) - ) : ( -
- {t("front:sideNav.noEvents")} -
- )} + + + {t("common:actions.viewAll")} + +
); } diff --git a/app/components/NotificationDot.module.css b/app/components/NotificationDot.module.css new file mode 100644 index 000000000..6f40e48b9 --- /dev/null +++ b/app/components/NotificationDot.module.css @@ -0,0 +1,33 @@ +.dot { + position: absolute; + top: var(--dot-top, -2px); + right: var(--dot-right, -2px); + width: 8px; + height: 8px; + background-color: var(--color-text-accent); + border-radius: 100%; + outline: 2px solid var(--color-bg); + pointer-events: none; +} + +.pulse { + display: block; + width: 100%; + height: 100%; + border-radius: 50%; + background-color: var(--color-text-accent); + box-shadow: 0 0 0 var(--color-text-accent); + animation: pulse 2s infinite; +} + +@keyframes pulse { + from { + box-shadow: 0 0 0 0 var(--color-text-accent); + } + 70% { + box-shadow: 0 0 0 10px rgba(255, 255, 255, 0); + } + to { + box-shadow: 0 0 0 0 rgba(255, 255, 255, 0); + } +} diff --git a/app/components/NotificationDot.tsx b/app/components/NotificationDot.tsx new file mode 100644 index 000000000..ff0151a2f --- /dev/null +++ b/app/components/NotificationDot.tsx @@ -0,0 +1,10 @@ +import clsx from "clsx"; +import styles from "./NotificationDot.module.css"; + +export function NotificationDot({ className }: { className?: string }) { + return ( + + + + ); +} diff --git a/app/components/SideNav.module.css b/app/components/SideNav.module.css index db1f322fe..d465206a8 100644 --- a/app/components/SideNav.module.css +++ b/app/components/SideNav.module.css @@ -28,6 +28,7 @@ align-items: center; padding-inline: var(--s-2); flex-shrink: 0; + overflow: hidden; } .sideNavTopCentered { @@ -121,35 +122,8 @@ } .sideNavFooterUnseenDot { - background-color: var(--color-text-accent); - border-radius: 100%; - width: 8px; - height: 8px; - position: absolute; - top: 2px; - right: 2px; - outline: 2px solid var(--color-bg-high); -} - -.sideNavFooterUnseenDotPulse { - width: 100%; - height: 100%; - border-radius: 50%; - background-color: var(--color-text-accent); - box-shadow: 0 0 0 var(--color-text-accent); - animation: pulse 2s infinite; -} - -@keyframes pulse { - from { - box-shadow: 0 0 0 0 inherit; - } - 70% { - box-shadow: 0 0 0 10px rgba(255, 255, 255, 0); - } - to { - box-shadow: 0 0 0 0 rgba(255, 255, 255, 0); - } + --dot-top: 2px; + --dot-right: 2px; } .sideNavHeader { diff --git a/app/components/SideNav.tsx b/app/components/SideNav.tsx index e9598ca10..7f19edb1d 100644 --- a/app/components/SideNav.tsx +++ b/app/components/SideNav.tsx @@ -121,7 +121,12 @@ export function ListLink({ {subtitle || badge ? (
{subtitle ? ( - {subtitle} + + {subtitle} + ) : null} {typeof badge === "string" ? ( void; }) { const { t, i18n } = useTranslation(["front"]); - const isMounted = useIsMounted(); const formatRelativeDate = (timestamp: number) => { const date = new Date(timestamp * 1000); @@ -60,7 +58,7 @@ export function StreamListItems({ const prevIsLive = prevStream && databaseTimestampToDate(prevStream.startsAt).getTime() <= Date.now(); - const showUpcomingDivider = isMounted && isUpcoming && prevIsLive; + const showUpcomingDivider = isUpcoming && prevIsLive; return ( @@ -85,22 +83,16 @@ export function StreamListItems({ ) : stream.subtitle ? ( stream.subtitle - ) : isMounted ? ( - isUpcoming ? ( - formatRelativeDate(stream.startsAt) - ) : ( - formatDistanceToNow(startsAtDate, { - addSuffix: true, - language: i18n.language as LanguageCode, - }) - ) + ) : isUpcoming ? ( + formatRelativeDate(stream.startsAt) ) : ( - "" + formatDistanceToNow(startsAtDate, { + addSuffix: true, + language: i18n.language as LanguageCode, + }) ) } - badge={ - isMounted && !isUpcoming ? "LIVE" : streamTierBadge(stream) - } + badge={!isUpcoming ? "LIVE" : streamTierBadge(stream)} onClick={onClick} > {stream.name} diff --git a/app/components/WeaponSelect.tsx b/app/components/WeaponSelect.tsx index 3ec0ebd3f..2921084e5 100644 --- a/app/components/WeaponSelect.tsx +++ b/app/components/WeaponSelect.tsx @@ -139,7 +139,7 @@ export function WeaponSelect< ? specialWeaponImageUrl(TRIZOOKA_ID) : weaponCategoryUrl(name) } - className={idx === 0 ? "pt-0-5-forced" : undefined} + className={idx === 0 ? "pt-0-5" : undefined} key={key} > {weapons.map(({ weapon, name }) => ( diff --git a/app/components/layout/NotificationPopover.module.css b/app/components/layout/NotificationPopover.module.css index 28693565f..7a5bb8c4b 100644 --- a/app/components/layout/NotificationPopover.module.css +++ b/app/components/layout/NotificationPopover.module.css @@ -44,3 +44,32 @@ .divider { border-color: var(--color-border); } + +.viewAllLink { + display: flex; + align-items: center; + gap: 2px; + width: fit-content; + margin: var(--s-2) auto; + font-size: var(--font-2xs); + color: var(--color-text-high); + text-decoration: none; + padding: var(--s-1) var(--s-3); + background-color: var(--color-bg-higher); + border-radius: var(--radius-field); + + & svg { + stroke-width: 3; + } +} + +@media screen and (max-width: 599px) { + .viewAllLink { + margin-top: var(--s-4); + } +} + +.viewAllLink:hover { + color: var(--color-text); + background-color: var(--color-bg-high); +} diff --git a/app/components/layout/NotificationPopover.tsx b/app/components/layout/NotificationPopover.tsx index f2468e51a..2d365f9b8 100644 --- a/app/components/layout/NotificationPopover.tsx +++ b/app/components/layout/NotificationPopover.tsx @@ -1,7 +1,7 @@ -import { Bell, RefreshCcw } from "lucide-react"; +import { Bell, ChevronRight, RefreshCcw } from "lucide-react"; import * as React from "react"; import { useTranslation } from "react-i18next"; -import { useMatches, useRevalidator } from "react-router"; +import { Link, useMatches, useRevalidator } from "react-router"; import { NotificationItem, NotificationItemDivider, @@ -11,7 +11,7 @@ import { NOTIFICATIONS } from "~/features/notifications/notifications-contants"; import type { RootLoaderData } from "~/root"; import { NOTIFICATIONS_URL } from "~/utils/urls"; import { useMarkNotificationsAsSeen } from "../../features/notifications/notifications-hooks"; -import { LinkButton, SendouButton } from "../elements/Button"; +import { SendouButton } from "../elements/Button"; import styles from "./NotificationPopover.module.css"; @@ -95,15 +95,15 @@ function NotificationsFooter({ onClose }: { onClose?: () => void }) { return (

- - {t("common:notifications.seeAll")} - + {t("common:actions.viewAll")} + +
); } diff --git a/app/components/layout/index.module.css b/app/components/layout/index.module.css index 6c054d872..8e3e8a61a 100644 --- a/app/components/layout/index.module.css +++ b/app/components/layout/index.module.css @@ -18,12 +18,18 @@ z-index: 10; } +.siteTitleFlipper { + min-width: 0; + overflow: hidden; +} + .siteTitle { display: flex; align-items: center; gap: var(--s-2); height: 100%; min-width: 0; + overflow: hidden; } .siteLogo { @@ -101,6 +107,7 @@ overflow: hidden; text-overflow: ellipsis; white-space: nowrap; + min-width: 0; animation: fadeInFull 200ms ease-out 150ms both; } @@ -135,6 +142,12 @@ } } +.sideNavCollapseButtonContainer { + position: relative; + --dot-top: 2px; + --dot-right: 2px; +} + /* Doubled selector increases specificity to beat Button.module.css's display: flex */ .sideNavCollapseButton.sideNavCollapseButton, .sideNavModalTrigger.sideNavModalTrigger { diff --git a/app/components/layout/index.tsx b/app/components/layout/index.tsx index 19ad07818..cd949b7fe 100644 --- a/app/components/layout/index.tsx +++ b/app/components/layout/index.tsx @@ -25,12 +25,18 @@ import { useUser } from "~/features/auth/core/user"; import { FriendMenu } from "~/features/friends/components/FriendMenu"; import type { RootLoaderData } from "~/root"; import type { Breadcrumb, SendouRouteHandle } from "~/utils/remix.server"; -import { FRIENDS_PAGE, SETTINGS_PAGE, userPage } from "~/utils/urls"; +import { + EVENTS_PAGE, + FRIENDS_PAGE, + SETTINGS_PAGE, + userPage, +} from "~/utils/urls"; import { Avatar } from "../Avatar"; import { SendouButton } from "../elements/Button"; import { SendouPopover } from "../elements/Popover"; import { Image } from "../Image"; import { MobileNav } from "../MobileNav"; +import { NotificationDot } from "../NotificationDot"; import { ListLink, SideNav, SideNavFooter, SideNavHeader } from "../SideNav"; import sideNavStyles from "../SideNav.module.css"; import { StreamListItems } from "../StreamListItems"; @@ -188,6 +194,7 @@ export function Layout({ }, []); const user = useUser(); + const { unseenIds } = useNotifications(); const sidebarData = data?.sidebar; const events = sidebarData?.events ?? []; const friends = sidebarData?.friends ?? []; @@ -208,7 +215,17 @@ export function Layout({ const sideNavChildren = ( <> - }> + } + action={ + user ? ( + + {t("common:actions.viewAll")} + + + ) : null + } + > {t("front:sideNav.myCalendar")} {events.length > 0 ? ( @@ -309,6 +326,7 @@ export function Layout({ setSideNavCollapsed(!sideNavCollapsed)} className={styles.sideNavCollapseButton} + showNotificationDot={sideNavCollapsed && unseenIds.length > 0} /> 0; return ( - +
@@ -376,19 +397,24 @@ function SiteLogoContent() { function SideNavCollapseButton({ onToggle, className, + showNotificationDot, }: { onToggle?: () => void; className?: string; + showNotificationDot?: boolean; }) { return ( - } - onPress={onToggle} - /> +
+ } + onPress={onToggle} + /> + {showNotificationDot ? : null} +
); } @@ -419,6 +445,7 @@ function MyRampUnit() { function SideNavUserPanel() { const { t } = useTranslation(); + const location = useLocation(); const user = useUser(); const { notifications, unseenIds } = useNotifications(); @@ -433,11 +460,14 @@ function SideNavUserPanel() {
{notifications ? ( -
+
{unseenIds.length > 0 ? ( -
-
-
+ ) : null} [ variation === "NO_SCRIMS" ? undefined : scrimPostRequests, associations, notifications, - friendships, + () => friendships(variation), liveStreams, ]; @@ -2800,7 +2800,7 @@ async function organization() { const SENDOU_FRIEND_IDS_IN_LOOKING_GROUPS = [150, 151, 152, 153]; const SENDOU_FRIEND_IDS_AS_TOURNAMENT_SUBS = [100, 101, 102, 103]; -async function friendships() { +async function friendships(variation?: SeedVariation | null) { const allFriendIds = [ ...SENDOU_FRIEND_IDS_IN_LOOKING_GROUPS, ...SENDOU_FRIEND_IDS_AS_TOURNAMENT_SUBS, @@ -2820,6 +2820,8 @@ async function friendships() { .run({ userOneId, userTwoId }); } + if (variation === "NO_SQ_GROUPS") return; + for (const friendId of SENDOU_FRIEND_IDS_IN_LOOKING_GROUPS) { const group = await SQGroupRepository.createGroup({ status: "ACTIVE", diff --git a/app/features/articles/routes/a.$slug.tsx b/app/features/articles/routes/a.$slug.tsx index 456010b8c..3fd8ead70 100644 --- a/app/features/articles/routes/a.$slug.tsx +++ b/app/features/articles/routes/a.$slug.tsx @@ -7,7 +7,6 @@ import invariant from "~/utils/invariant"; import type { SendouRouteHandle } from "~/utils/remix.server"; import { ARTICLES_MAIN_PAGE, - articlePage, articlePreviewUrl, navIconUrl, } from "~/utils/urls"; @@ -28,11 +27,6 @@ export const handle: SendouRouteHandle = { href: ARTICLES_MAIN_PAGE, type: "IMAGE", }, - { - text: data.title, - href: articlePage(data.slug), - type: "TEXT", - }, ]; }, }; @@ -64,12 +58,38 @@ export default function ArticlePage() {
by
- {data.content} + + {contentWithoutLeadingTitle(data.content, data.title)} + ); } +function normalizeText(text: string) { + return text + .replace(/\*+/g, "") + .replace(/…/g, "...") + .replace(/\\!/g, "!") + .trim(); +} + +function contentWithoutLeadingTitle(content: string, title: string) { + const trimmed = content.trimStart(); + const firstLineEnd = trimmed.indexOf("\n"); + const firstLine = + firstLineEnd === -1 ? trimmed : trimmed.slice(0, firstLineEnd); + + if ( + firstLine.startsWith("# ") && + normalizeText(firstLine.slice(2)) === normalizeText(title) + ) { + return trimmed.slice(firstLine.length).trimStart(); + } + + return content; +} + function Author() { const data = useLoaderData(); diff --git a/app/features/badges/routes/badges.$id.edit.tsx b/app/features/badges/routes/badges.$id.edit.tsx index 989661b08..c7aea85de 100644 --- a/app/features/badges/routes/badges.$id.edit.tsx +++ b/app/features/badges/routes/badges.$id.edit.tsx @@ -25,7 +25,6 @@ export default function EditBadgePage() {
{isStaff ? : null} @@ -53,13 +52,13 @@ function Managers({ data }: { data: BadgeDetailsLoaderData }) { ).length; return ( -
+

Managers

m.id).join("-")} label="Add new manager" - className="text-center mx-auto" + className="text-center" name="new-manager" onChange={(user) => { if (!user) return; @@ -134,12 +133,12 @@ function Owners({ data }: { data: BadgeDetailsLoaderData }) { const userInputKey = owners.map((o) => `${o.id}-${o.count}`).join("-"); return ( -
+

Owners

{ diff --git a/app/features/build-stats/routes/builds.$slug.popular.tsx b/app/features/build-stats/routes/builds.$slug.popular.tsx index 3ec863915..9a0aeff9f 100644 --- a/app/features/build-stats/routes/builds.$slug.popular.tsx +++ b/app/features/build-stats/routes/builds.$slug.popular.tsx @@ -45,11 +45,6 @@ export const handle: SendouRouteHandle = { href: weaponBuildPage(data.meta.slug), type: "IMAGE", }, - { - href: "/", - text: data.meta.breadcrumbText, - type: "TEXT", - }, ]; }, }; diff --git a/app/features/build-stats/routes/builds.$slug.stats.tsx b/app/features/build-stats/routes/builds.$slug.stats.tsx index 4c0cc7966..83823e5cd 100644 --- a/app/features/build-stats/routes/builds.$slug.stats.tsx +++ b/app/features/build-stats/routes/builds.$slug.stats.tsx @@ -48,11 +48,6 @@ export const handle: SendouRouteHandle = { href: weaponBuildPage(data.meta.slug), type: "IMAGE", }, - { - href: "/", - text: data.meta.breadcrumbText, - type: "TEXT", - }, ]; }, }; diff --git a/app/features/calendar/loaders/events.server.ts b/app/features/calendar/loaders/events.server.ts new file mode 100644 index 000000000..a201e6108 --- /dev/null +++ b/app/features/calendar/loaders/events.server.ts @@ -0,0 +1,32 @@ +import { requireUser } from "~/features/auth/core/user.server"; +import * as ShowcaseTournaments from "~/features/front-page/core/ShowcaseTournaments.server"; +import * as ScrimPostRepository from "~/features/scrims/ScrimPostRepository.server"; +import { + scrimToSidebarEvent, + tournamentToSidebarEvent, +} from "~/features/sidebar/core/sidebar.server"; + +export type EventsLoaderData = typeof loader; + +export const loader = async () => { + const user = requireUser(); + + const [tournamentsData, scrimsData] = await Promise.all([ + ShowcaseTournaments.frontPageTournamentsByUserId(user.id), + ScrimPostRepository.findUserScrims(user.id), + ]); + + const registered = tournamentsData.participatingFor + .map(tournamentToSidebarEvent) + .sort((a, b) => a.startTime - b.startTime); + + const hosting = tournamentsData.organizingFor + .map(tournamentToSidebarEvent) + .sort((a, b) => a.startTime - b.startTime); + + const scrims = scrimsData + .map(scrimToSidebarEvent) + .sort((a, b) => a.startTime - b.startTime); + + return { registered, hosting, scrims }; +}; diff --git a/app/features/calendar/routes/events.module.css b/app/features/calendar/routes/events.module.css new file mode 100644 index 000000000..44bb705a9 --- /dev/null +++ b/app/features/calendar/routes/events.module.css @@ -0,0 +1,22 @@ +.eventsListHeader { + display: flex; + align-items: center; + justify-content: space-between; + flex-wrap: wrap; + gap: var(--s-2); + margin-block-end: var(--s-2); +} + +.filterRadio { + padding: var(--s-1) var(--s-2); + border-radius: var(--radius-field); + cursor: pointer; + color: var(--color-text-high); + font-weight: var(--weight-semi); + font-size: var(--font-3xs); +} + +.filterRadioSelected { + background-color: var(--color-bg-higher); + color: var(--color-text); +} diff --git a/app/features/calendar/routes/events.tsx b/app/features/calendar/routes/events.tsx new file mode 100644 index 000000000..b8a801022 --- /dev/null +++ b/app/features/calendar/routes/events.tsx @@ -0,0 +1,83 @@ +import clsx from "clsx"; +import { useState } from "react"; +import { Radio, RadioGroup } from "react-aria-components"; +import { useTranslation } from "react-i18next"; +import { Link, useLoaderData } from "react-router"; +import { EventsList } from "~/components/EventsList"; +import { Main } from "~/components/Main"; +import type { SendouRouteHandle } from "~/utils/remix.server"; +import { CALENDAR_PAGE } from "~/utils/urls"; +import type { EventsLoaderData } from "../loaders/events.server"; +import styles from "./events.module.css"; + +export { loader } from "../loaders/events.server"; + +export const handle: SendouRouteHandle = { + i18n: ["calendar"], +}; + +type ViewFilter = "registered" | "hosting" | "scrims"; + +export default function EventsPage() { + const { t } = useTranslation(["calendar"]); + const data = useLoaderData(); + const [filter, setFilter] = useState("registered"); + + const viewLabels: Record = { + registered: t("calendar:events.view.registered"), + hosting: t("calendar:events.view.hosting"), + scrims: t("calendar:events.view.scrims"), + }; + + const shownEvents = + filter === "registered" + ? data.registered + : filter === "hosting" + ? data.hosting + : data.scrims; + + const hasNoEventsAtAll = + data.registered.length === 0 && + data.hosting.length === 0 && + data.scrims.length === 0; + + return ( +
+
+

{t("calendar:events.title")}

+ {hasNoEventsAtAll ? null : ( + setFilter(v as ViewFilter)} + orientation="horizontal" + className="stack horizontal xs" + > + {(["registered", "hosting", "scrims"] as const).map((value) => ( + + {({ isSelected }) => ( + + {viewLabels[value]} + + )} + + ))} + + )} +
+ {hasNoEventsAtAll ? ( +

+ {t("calendar:events.emptyAll")}{" "} + {t("calendar:events.findOnCalendar")} +

+ ) : shownEvents.length === 0 ? ( +

{t("calendar:events.empty")}

+ ) : ( + + )} +
+ ); +} diff --git a/app/features/core/streams/streams.server.ts b/app/features/core/streams/streams.server.ts index 7c5077b47..c4a3b0b90 100644 --- a/app/features/core/streams/streams.server.ts +++ b/app/features/core/streams/streams.server.ts @@ -44,10 +44,10 @@ export function getLiveTournamentStreams(): SidebarStream[] { return streams; } -// xxx: not always reporting furthest round function deriveCurrentRound(tournament: Tournament): string { - for (const bracket of tournament.brackets) { + for (const bracket of tournament.brackets.toReversed()) { if (bracket.preview) continue; + if (bracket.isUnderground) continue; for (const match of bracket.data.match) { const isActive = diff --git a/app/features/sidebar/core/sidebar.server.ts b/app/features/sidebar/core/sidebar.server.ts index 5076909a1..0192e1da5 100644 --- a/app/features/sidebar/core/sidebar.server.ts +++ b/app/features/sidebar/core/sidebar.server.ts @@ -12,6 +12,7 @@ import * as FriendRepository from "~/features/friends/FriendRepository.server"; import { resolveFriendActivity } from "~/features/friends/friends-utils.server"; import * as ShowcaseTournaments from "~/features/front-page/core/ShowcaseTournaments.server"; import * as LiveStreamRepository from "~/features/live-streams/LiveStreamRepository.server"; +import type { SidebarScrim } from "~/features/scrims/ScrimPostRepository.server"; import * as ScrimPostRepository from "~/features/scrims/ScrimPostRepository.server"; import { getSendouQSidebarStreams } from "~/features/sendouq-streams/core/streams.server"; import type { TournamentTierNumber } from "~/features/tournament/core/tiering"; @@ -81,27 +82,9 @@ export async function resolveSidebarData(userId: number | null) { seenTournamentIds.add(t.id); return true; }) - .map((t) => ({ - id: t.id, - name: t.name, - url: t.url, - logoUrl: t.logoUrl, - startTime: t.startTime, - type: "tournament" as const, - })); + .map(tournamentToSidebarEvent); - const scrimsIconUrl = `${navIconUrl("scrims")}.png`; - const scrimEvents: SidebarEvent[] = scrimsData.map((s) => ({ - id: s.id, - name: s.opponentName ?? "Scrim", - url: s.isAccepted - ? href("/scrims/:id", { id: String(s.id) }) - : href("/scrims"), - logoUrl: s.opponentAvatarUrl ?? scrimsIconUrl, - startTime: s.at, - type: "scrim" as const, - scrimStatus: s.isAccepted ? ("booked" as const) : ("looking" as const), - })); + const scrimEvents: SidebarEvent[] = scrimsData.map(scrimToSidebarEvent); const personalEvents = [...tournamentEvents, ...scrimEvents].sort( (a, b) => a.startTime - b.startTime, @@ -347,3 +330,32 @@ function rowToSidebarFriend( tournamentId: row.tournamentId, }; } + +export function tournamentToSidebarEvent( + t: ShowcaseCalendarEvent, +): SidebarEvent { + return { + id: t.id, + name: t.name, + url: t.url, + logoUrl: t.logoUrl, + startTime: t.startTime, + type: "tournament" as const, + }; +} + +const SCRIMS_ICON_URL = `${navIconUrl("scrims")}.png`; + +export function scrimToSidebarEvent(s: SidebarScrim): SidebarEvent { + return { + id: s.id, + name: s.opponentName ?? "Scrim", + url: s.isAccepted + ? href("/scrims/:id", { id: String(s.id) }) + : href("/scrims"), + logoUrl: s.opponentAvatarUrl ?? SCRIMS_ICON_URL, + startTime: s.at, + type: "scrim" as const, + scrimStatus: s.isAccepted ? ("booked" as const) : ("looking" as const), + }; +} diff --git a/app/features/team/actions/t.$customUrl.edit.server.ts b/app/features/team/actions/t.$customUrl.edit.server.ts index 9df37ad1c..56b8dde0b 100644 --- a/app/features/team/actions/t.$customUrl.edit.server.ts +++ b/app/features/team/actions/t.$customUrl.edit.server.ts @@ -8,7 +8,7 @@ import { parseRequestPayload, } from "~/utils/remix.server"; import { assertUnreachable } from "~/utils/types"; -import { mySlugify, TEAM_SEARCH_PAGE, teamPage } from "~/utils/urls"; +import { mySlugify, teamPage } from "~/utils/urls"; import * as TeamRepository from "../TeamRepository.server"; import { editTeamSchema, teamParamsSchema } from "../team-schemas.server"; import { @@ -60,7 +60,7 @@ export const action: ActionFunction = async ({ request, params }) => { } case "DELETE_TEAM": { await TeamRepository.del(team.id); - throw redirect(TEAM_SEARCH_PAGE); + throw redirect("/"); } case "DELETE_AVATAR": { await TeamRepository.removeTeamImage(team.id, "avatar"); diff --git a/app/features/theme/core/provider.tsx b/app/features/theme/core/provider.tsx index f8ea4a96a..506974624 100644 --- a/app/features/theme/core/provider.tsx +++ b/app/features/theme/core/provider.tsx @@ -15,7 +15,7 @@ type Theme = (typeof Theme)[keyof typeof Theme]; const themes = Object.values(Theme); type ThemeContextType = { - htmlThemeClass: Theme; + htmlThemeClass: Theme | ""; metaColorScheme: "light dark" | "dark light"; userTheme: Theme | "auto" | null; setUserTheme: (newTheme: Theme | "auto") => void; @@ -39,7 +39,7 @@ function useSystemTheme() { return useSyncExternalStore( subscribeToSystemTheme, getSystemTheme, - () => Theme.DARK, + () => null, ); } @@ -49,7 +49,7 @@ type ThemeProviderProps = { themeSource: "user-preference" | "static"; }; -function colorScheme(theme: Theme) { +function colorScheme(theme: Theme | "") { return theme === Theme.LIGHT ? "light dark" : "dark light"; } @@ -66,10 +66,10 @@ function ThemeProvider({ const systemTheme = useSystemTheme(); const persistThemeFetcher = useFetcher(); - const resolvedTheme = isStatic + const resolvedTheme: Theme | "" = isStatic ? (specifiedTheme ?? Theme.DARK) : userPreference === "auto" - ? systemTheme + ? (systemTheme ?? "") : userPreference; const handleSetUserTheme = (newTheme: Theme | "auto") => { diff --git a/app/features/tournament-bracket/components/Bracket/Match.tsx b/app/features/tournament-bracket/components/Bracket/Match.tsx index 3005d66f3..652bbef38 100644 --- a/app/features/tournament-bracket/components/Bracket/Match.tsx +++ b/app/features/tournament-bracket/components/Bracket/Match.tsx @@ -238,7 +238,7 @@ function MatchRow({ >
diff --git a/app/features/tournament/routes/to.$id.register.tsx b/app/features/tournament/routes/to.$id.register.tsx index 8b2f3717a..a5006b155 100644 --- a/app/features/tournament/routes/to.$id.register.tsx +++ b/app/features/tournament/routes/to.$id.register.tsx @@ -439,7 +439,7 @@ function RegistrationProgress({
- {steps.map((step) => { + {steps.map((step, i) => { return (
) : step.status === "notice" ? ( {tournament.ctx.settings.requireInGameNames ? ( -
+
Note that you are expected to use the in-game names as listed above. Playing in the event with a different name or using the alias feature might result in disqualification. diff --git a/app/features/tournament/routes/to.$id.tsx b/app/features/tournament/routes/to.$id.tsx index 97f633a99..5ba782dc6 100644 --- a/app/features/tournament/routes/to.$id.tsx +++ b/app/features/tournament/routes/to.$id.tsx @@ -19,7 +19,6 @@ import { removeMarkdown } from "~/utils/strings"; import { assertUnreachable } from "~/utils/types"; import { tournamentDivisionsPage, - tournamentOrganizationPage, tournamentPage, tournamentRegisterPage, } from "~/utils/urls"; @@ -70,24 +69,13 @@ export const handle: SendouRouteHandle = { const data = JSON.parse(rawData) as TournamentLoaderData; return [ - data.tournament.ctx.organization?.logoUrl - ? { - imgPath: data.tournament.ctx.organization.logoUrl, - href: tournamentOrganizationPage({ - organizationSlug: data.tournament.ctx.organization.slug, - }), - type: "IMAGE" as const, - text: "", - rounded: true, - } - : null, { imgPath: data.tournament.ctx.logoUrl, href: tournamentPage(data.tournament.ctx.id), type: "IMAGE" as const, text: data.tournament.ctx.name, }, - ].filter((crumb) => crumb !== null); + ]; }, }; diff --git a/app/features/user-page/routes/u.$identifier.tsx b/app/features/user-page/routes/u.$identifier.tsx index 94790a560..51ab36e71 100644 --- a/app/features/user-page/routes/u.$identifier.tsx +++ b/app/features/user-page/routes/u.$identifier.tsx @@ -8,6 +8,7 @@ import { useHasRole } from "~/modules/permissions/hooks"; import { metaTags } from "~/utils/remix"; import type { SendouRouteHandle } from "~/utils/remix.server"; import { + discordAvatarUrl, userAdminPage, userArtPage, userBuildsPage, @@ -44,10 +45,23 @@ export const handle: SendouRouteHandle = { if (!data) return []; + if (!data.user.discordAvatar) { + return { + text: data.user.username, + href: userPage(data.user), + type: "TEXT", + }; + } + return { - text: data.user.username, + imgPath: discordAvatarUrl({ + discordId: data.user.discordId, + discordAvatar: data.user.discordAvatar, + size: "sm", + }), href: userPage(data.user), - type: "TEXT", + type: "IMAGE", + text: data.user.username, }; }, }; diff --git a/app/root.tsx b/app/root.tsx index 1aa098646..3cd131bf7 100644 --- a/app/root.tsx +++ b/app/root.tsx @@ -164,6 +164,7 @@ function Document({ dir={i18n.dir()} className={clsx(htmlThemeClass, "scrollbar")} style={Object.fromEntries(customThemeStyle)} + suppressHydrationWarning > diff --git a/app/routes.ts b/app/routes.ts index 13eadc395..344e559c9 100644 --- a/app/routes.ts +++ b/app/routes.ts @@ -44,6 +44,8 @@ export default [ route("/friends", "features/friends/routes/friends.tsx"), + route("/events", "features/calendar/routes/events.tsx"), + route("/suspended", "features/ban/routes/suspended.tsx"), route("/u", "features/user-search/routes/u.tsx"), diff --git a/app/styles/common.css b/app/styles/common.css index 018be8682..fb8211bd5 100644 --- a/app/styles/common.css +++ b/app/styles/common.css @@ -1,569 +1,585 @@ /** biome-ignore-all lint/style/noDescendingSpecificity: Biome v2 migration */ +@layer base { + * { + margin: 0; + overflow-wrap: break-word; + } -* { - margin: 0; - overflow-wrap: break-word; -} - -html { - color-scheme: light dark; - accent-color: var(--color-text-accent); - scrollbar-gutter: stable; - scroll-padding-top: var(--layout-nav-height); -} - -@media screen and (display-mode: standalone) { html { - scroll-padding-top: calc( - var(--layout-nav-height) + - env(safe-area-inset-top) - ); - } -} - -body { - width: 100%; - min-height: 100vh; - display: flex; - line-height: var(--line-height); - overflow-x: hidden; - color: var(--color-text); - background-color: var(--color-bg); - font-family: lexend, sans-serif; - - -moz-osx-font-smoothing: antialiased; - -webkit-font-smoothing: antialiased; - -webkit-tab-highlight-color: transparent; - -webkit-text-size-adjust: 100%; -} - -h1, -h2, -h3, -h4, -h5, -h6, -p { - overflow-wrap: anywhere; -} - -img, -svg, -canvas, -video, -audio, -iframe, -embed, -object { - display: block; - max-width: 100%; -} - -input, -button, -textarea, -select { - font: inherit; - color: inherit; -} - -details summary { - cursor: pointer; - user-select: none; - -webkit-user-select: none; -} - -a { - color: var(--color-text-accent); - text-decoration: none; - border-radius: var(--radius-field); - - &:focus-visible { - outline: var(--focus-ring); - outline-offset: 1px; - } -} - -/* :not([name="text"]) workaround not to select textarea on map planner */ -textarea:not([name="text"]) { - width: 100%; - min-height: 8rem; - padding: var(--field-padding); - border: var(--border-style); - border-radius: var(--radius-field); - background-color: var(--color-bg); - font-size: var(--font-sm); - outline: none; - resize: vertical; - - &:focus-within { - outline: var(--focus-ring); - outline-offset: 1px; - } -} - -.input-container { - display: flex; - border: var(--border-style); - border-radius: var(--radius-field); - background-color: var(--color-bg); - height: var(--field-size); - font-size: var(--font-sm); - outline: none; -} - -.input-container:focus-within { - outline: var(--focus-ring); - outline-offset: 1px; -} - -.in-container { - width: 100%; - padding: 0 var(--field-padding); - border: none; - background: transparent; - margin: auto 0; - outline: none; -} - -.input-addon { - --addon-radius: calc(var(--radius-field) - 2px); - display: grid; - border-radius: var(--addon-radius) 0 0 var(--addon-radius); - background-color: var(--color-bg-high); - color: var(--color-text-high); - font-size: var(--font-sm); - padding-inline: var(--field-padding); - place-items: center; - white-space: nowrap; -} - -input:not(.in-container) { - width: 100%; - box-sizing: border-box; - border: var(--border-style); - border-radius: var(--radius-field); - background: var(--color-bg); - padding: 0 var(--field-padding); - height: var(--field-size); - font-size: var(--font-sm); - outline: none; - - &::placeholder { - color: var(--color-text-high); + color-scheme: light dark; + accent-color: var(--color-text-accent); + scrollbar-gutter: stable; + scroll-padding-top: var(--layout-nav-height); } - &:disabled { - pointer-events: none; - cursor: not-allowed; - opacity: 0.5; - outline: none; - } - - &:focus-within:not(:read-only) { - outline: var(--focus-ring); - outline-offset: 1px; - } -} - -input[type="checkbox"] { - appearance: none; - cursor: pointer; - padding: 0; - width: var(--selector-size-sm); - height: var(--selector-size-sm); - border-radius: calc(var(--radius-selector) / 2); - background-color: var(--color-bg); - border: var(--border-style); - - &:focus-within { - outline: none; - } - - &:focus-visible { - outline: var(--focus-ring); - outline-offset: 1px; - } - - &:checked, - &:indeterminate { - border-color: var(--color-text-accent); - background-color: var(--color-text-accent); - background-repeat: no-repeat; - background-position: center; - background-size: var(--field-size-icon) auto; - } - - &:checked { - background-image: var(--field-icon-checkbox); - } - - &:indeterminate { - background-image: var(--field-icon-minus); - } - - /* Hacky selector to remove the margin bottom from the container from Label.tsx */ - &:has(+ div > label) + div { - margin-bottom: 0; - } -} - -input[type="radio"] { - appearance: none; - cursor: pointer; - vertical-align: middle; - width: var(--selector-size-sm); - height: var(--selector-size-sm); - background-color: var(--color-bg); - border: var(--border-style); - border-radius: var(--radius-full); - padding: 0; - - &:focus-within { - outline: none; - } - - &:focus-visible { - outline: var(--focus-ring); - outline-offset: 1px; - } - - &::after { - content: ""; - display: block; - width: 50%; - height: 50%; - border-radius: var(--radius-full); - background-color: var(--color-bg); - margin: auto; - margin-top: 25%; - } - - &:checked { - border-color: var(--color-text-accent); - - &::after { - background-color: var(--color-text-accent); + @media screen and (display-mode: standalone) { + html { + scroll-padding-top: calc( + var(--layout-nav-height) + + env(safe-area-inset-top) + ); } } - /* Hacky selector to remove the margin bottom from the container from Label.tsx */ - &:has(+ div > label) + div { - margin-bottom: 0; - } -} + body { + width: 100%; + min-height: 100vh; + display: flex; + line-height: var(--line-height); + overflow-x: hidden; + color: var(--color-text); + background-color: var(--color-bg); + font-family: lexend, sans-serif; -label { - display: block; - font-size: var(--font-xs); - font-weight: var(--weight-bold); - margin-block-end: var(--label-margin); -} - -fieldset { - border: none; - border-radius: var(--radius-box); - background-color: var(--color-bg-high); - font-size: var(--font-sm); - padding-block-end: var(--s-3); - padding-inline: var(--s-3); -} - -legend { - border-radius: var(--radius-field); - background-color: transparent; - font-size: var(--font-xs); - font-weight: var(--weight-bold); -} - -article { - white-space: pre-wrap; -} - -select { - all: unset; - width: 100%; - box-sizing: border-box; - border: var(--border-style); - border-radius: var(--radius-field); - background-color: var(--color-bg); - cursor: pointer; - padding: 0 var(--field-padding); - padding-right: calc( - var(--field-size-icon) + - var(--field-padding) + - var(--s-2) - ); - height: var(--field-size); - font-size: var(--font-sm); - display: inline-flex; - align-items: center; - text-overflow: ellipsis; - white-space: nowrap; - appearance: none; - overflow: hidden; - - @supports (appearance: base-select) { - appearance: base-select; + -moz-osx-font-smoothing: antialiased; + -webkit-font-smoothing: antialiased; + -webkit-tab-highlight-color: transparent; + -webkit-text-size-adjust: 100%; } - &:disabled { - pointer-events: none; - cursor: not-allowed; - opacity: 0.5; + h1, + h2, + h3, + h4, + h5, + h6, + p { + overflow-wrap: anywhere; + } + + h1, + h2, + h3 { + text-wrap: balance; + } + p { + text-wrap: pretty; + } + + img, + svg, + canvas, + video, + audio, + iframe, + embed, + object { + display: block; + max-width: 100%; + } + + input, + button, + textarea, + select { + font: inherit; + color: inherit; + } + + details summary { + cursor: pointer; + user-select: none; + -webkit-user-select: none; + } + + a { + color: var(--color-text-accent); + text-decoration: none; + border-radius: var(--radius-field); + + &:focus-visible { + outline: var(--focus-ring); + outline-offset: 1px; + } + } + + /* :not([name="text"]) workaround not to select textarea on map planner */ + textarea:not([name="text"]) { + width: 100%; + min-height: 8rem; + padding: var(--field-padding); + border: var(--border-style); + border-radius: var(--radius-field); + background-color: var(--color-bg); + font-size: var(--font-sm); + outline: none; + resize: vertical; + + &:focus-within { + outline: var(--focus-ring); + outline-offset: 1px; + } + } + + .input-container { + display: flex; + border: var(--border-style); + border-radius: var(--radius-field); + background-color: var(--color-bg); + height: var(--field-size); + font-size: var(--font-sm); outline: none; } - &:focus-within { + .input-container:focus-within { outline: var(--focus-ring); outline-offset: 1px; } - /* biome-ignore lint: experimental CSS feature */ - &::picker(select) { + .in-container { + width: 100%; + padding: 0 var(--field-padding); + border: none; + background: transparent; + margin: auto 0; + outline: none; + } + + .input-addon { + --addon-radius: calc(var(--radius-field) - 2px); + display: grid; + border-radius: var(--addon-radius) 0 0 var(--addon-radius); + background-color: var(--color-bg-high); + color: var(--color-text-high); + font-size: var(--font-sm); + padding-inline: var(--field-padding); + place-items: center; + white-space: nowrap; + } + + input:not(.in-container) { + width: 100%; + box-sizing: border-box; + border: var(--border-style); + border-radius: var(--radius-field); + background: var(--color-bg); + padding: 0 var(--field-padding); + height: var(--field-size); + font-size: var(--font-sm); + outline: none; + + &::placeholder { + color: var(--color-text-high); + } + + &:disabled { + pointer-events: none; + cursor: not-allowed; + opacity: 0.5; + outline: none; + } + + &:focus-within:not(:read-only) { + outline: var(--focus-ring); + outline-offset: 1px; + } + } + + input[type="checkbox"] { + appearance: none; + cursor: pointer; + padding: 0; + width: var(--selector-size-sm); + height: var(--selector-size-sm); + border-radius: calc(var(--radius-selector) / 2); + background-color: var(--color-bg); + border: var(--border-style); + + &:focus-within { + outline: none; + } + + &:focus-visible { + outline: var(--focus-ring); + outline-offset: 1px; + } + + &:checked, + &:indeterminate { + border-color: var(--color-text-accent); + background-color: var(--color-text-accent); + background-repeat: no-repeat; + background-position: center; + background-size: var(--field-size-icon) auto; + } + + &:checked { + background-image: var(--field-icon-checkbox); + } + + &:indeterminate { + background-image: var(--field-icon-minus); + } + + /* Hacky selector to remove the margin bottom from the container from Label.tsx */ + &:has(+ div > label) + div { + margin-bottom: 0; + } + } + + input[type="radio"] { + appearance: none; + cursor: pointer; + vertical-align: middle; + width: var(--selector-size-sm); + height: var(--selector-size-sm); + background-color: var(--color-bg); + border: var(--border-style); + border-radius: var(--radius-full); + padding: 0; + + &:focus-within { + outline: none; + } + + &:focus-visible { + outline: var(--focus-ring); + outline-offset: 1px; + } + + &::after { + content: ""; + display: block; + width: 50%; + height: 50%; + border-radius: var(--radius-full); + background-color: var(--color-bg); + margin: auto; + margin-top: 25%; + } + + &:checked { + border-color: var(--color-text-accent); + + &::after { + background-color: var(--color-text-accent); + } + } + + /* Hacky selector to remove the margin bottom from the container from Label.tsx */ + &:has(+ div > label) + div { + margin-bottom: 0; + } + } + + label { + display: block; + font-size: var(--font-xs); + font-weight: var(--weight-bold); + margin-block-end: var(--label-margin); + } + + fieldset { + border: none; + border-radius: var(--radius-box); + background-color: var(--color-bg-high); + font-size: var(--font-sm); + padding-block-end: var(--s-3); + padding-inline: var(--s-3); + } + + legend { + border-radius: var(--radius-field); + background-color: transparent; + font-size: var(--font-xs); + font-weight: var(--weight-bold); + } + + article { + white-space: pre-wrap; + } + + select { + all: unset; + width: 100%; + box-sizing: border-box; + border: var(--border-style); + border-radius: var(--radius-field); + background-color: var(--color-bg); + cursor: pointer; + padding: 0 var(--field-padding); + padding-right: calc( + var(--field-size-icon) + + var(--field-padding) + + var(--s-2) + ); + height: var(--field-size); + font-size: var(--font-sm); + display: inline-flex; + align-items: center; + text-overflow: ellipsis; + white-space: nowrap; + appearance: none; + overflow: hidden; + @supports (appearance: base-select) { appearance: base-select; } - background-color: var(--color-bg); - border: var(--border-style); - border-radius: var(--radius-field); - padding: var(--s-1); - margin: 0.5rem; - translate: -0.5rem; - max-height: 50dvh; - } - - /* biome-ignore lint: experimental CSS feature */ - &::picker-icon { - display: none; - } - - option { - background-color: var(--color-bg); - color: var(--color-text); - border-radius: var(--radius-field); - font-size: var(--font-sm); - font-weight: var(--weight-semi); - padding: var(--s-1-5); - white-space: nowrap; - text-overflow: ellipsis; - overflow: hidden; - - &[disabled] { - color: var(--color-text-high); + &:disabled { + pointer-events: none; + cursor: not-allowed; + opacity: 0.5; + outline: none; } - &:hover:not([disabled]) { - background-color: var(--color-bg-high); + &:focus-within { + outline: var(--focus-ring); + outline-offset: 1px; + } + + /* biome-ignore lint: experimental CSS feature */ + &::picker(select) { + @supports (appearance: base-select) { + appearance: base-select; + } + + background-color: var(--color-bg); + border: var(--border-style); + border-radius: var(--radius-field); + padding: var(--s-1); + margin: 0.5rem; + translate: -0.5rem; + max-height: 50dvh; + } + + /* biome-ignore lint: experimental CSS feature */ + &::picker-icon { + display: none; + } + + option { + background-color: var(--color-bg); + color: var(--color-text); + border-radius: var(--radius-field); + font-size: var(--font-sm); + font-weight: var(--weight-semi); + padding: var(--s-1-5); + white-space: nowrap; + text-overflow: ellipsis; + overflow: hidden; + + &[disabled] { + color: var(--color-text-high); + } + + &:hover:not([disabled]) { + background-color: var(--color-bg-high); + } } } -} -input[type="date"], -input[type="datetime-local"], -input[type="month"], -input[type="time"], -input[type="week"], -select { - background-position: center right var(--field-padding); - background-size: var(--field-size-icon) auto; - background-repeat: no-repeat; -} - -input[type="date"], -input[type="datetime-local"], -input[type="month"], -input[type="week"] { - background-image: var(--field-icon-date); -} - -input[type="time"] { - background-image: var(--field-icon-time); -} - -select { - background-image: var(--field-icon-chevron); -} - -[type="date"]::-webkit-calendar-picker-indicator, -[type="datetime-local"]::-webkit-calendar-picker-indicator, -[type="month"]::-webkit-calendar-picker-indicator, -[type="time"]::-webkit-calendar-picker-indicator, -[type="week"]::-webkit-calendar-picker-indicator { - width: var(--field-size-icon); - opacity: 0; -} - -@-moz-document url-prefix() { - [type="date"], - [type="datetime-local"], - [type="month"], - [type="time"], - [type="week"] { - background-image: none !important; - } -} - -@-moz-document url-prefix() { input[type="date"], input[type="datetime-local"], input[type="month"], input[type="time"], + input[type="week"], + select { + background-position: center right var(--field-padding); + background-size: var(--field-size-icon) auto; + background-repeat: no-repeat; + } + + input[type="date"], + input[type="datetime-local"], + input[type="month"], input[type="week"] { - background-image: none; - } -} - -input[type="color"] { - padding: calc(var(--field-size) / 8) var(--field-padding); -} - -input[type="color"]::-webkit-color-swatch { - border: 0; - border-radius: var(--radius-field); -} - -input[type="color"]::-moz-color-swatch { - border: 0; - border-radius: var(--radius-field); -} - -input[type="file"] { - padding: 0; - cursor: pointer; - font-size: var(--font-sm); - color: var(--color-text-high); - overflow: hidden; -} - -input[type="file"]::file-selector-button { - height: 100%; - border: none; - background-color: var(--color-bg-higher); - white-space: nowrap; - margin-right: var(--s-2); -} - -input[type="range"] { - --track-color: var(--color-bg-higher); - --thumb-color: var(--color-text-high); - border: none; - padding: 0; - appearance: none; - background: 0 0; - width: 100%; - height: var(--selector-size); - - &:focus { - outline: none; + background-image: var(--field-icon-date); } - &:focus-within { + input[type="time"] { + background-image: var(--field-icon-time); + } + + select { + background-image: var(--field-icon-chevron); + } + + [type="date"]::-webkit-calendar-picker-indicator, + [type="datetime-local"]::-webkit-calendar-picker-indicator, + [type="month"]::-webkit-calendar-picker-indicator, + [type="time"]::-webkit-calendar-picker-indicator, + [type="week"]::-webkit-calendar-picker-indicator { + width: var(--field-size-icon); + opacity: 0; + } + + @-moz-document url-prefix() { + [type="date"], + [type="datetime-local"], + [type="month"], + [type="time"], + [type="week"] { + background-image: none !important; + } + } + + @-moz-document url-prefix() { + input[type="date"], + input[type="datetime-local"], + input[type="month"], + input[type="time"], + input[type="week"] { + background-image: none; + } + } + + input[type="color"] { + padding: calc(var(--field-size) / 8) var(--field-padding); + } + + input[type="color"]::-webkit-color-swatch { + border: 0; + border-radius: var(--radius-field); + } + + input[type="color"]::-moz-color-swatch { + border: 0; + border-radius: var(--radius-field); + } + + input[type="file"] { + padding: 0; + cursor: pointer; + font-size: var(--font-sm); + color: var(--color-text-high); + overflow: hidden; + } + + input[type="file"]::file-selector-button { + height: 100%; + border: none; + background-color: var(--color-bg-higher); + white-space: nowrap; + margin-right: var(--s-2); + } + + input[type="range"] { --track-color: var(--color-bg-higher); - --thumb-color: var(--color-text-accent); + --thumb-color: var(--color-text-high); + border: none; + padding: 0; + appearance: none; + background: 0 0; + width: 100%; + height: var(--selector-size); + + &:focus { + outline: none; + } + + &:focus-within { + --track-color: var(--color-bg-higher); + --thumb-color: var(--color-text-accent); + } } -} -input[type="range"]::-webkit-slider-runnable-track { - width: 100%; - height: calc(var(--selector-size) / 4); - background-color: var(--track-color); - border-radius: var(--radius-full); - transition: 100ms background-color; -} + input[type="range"]::-webkit-slider-runnable-track { + width: 100%; + height: calc(var(--selector-size) / 4); + background-color: var(--track-color); + border-radius: var(--radius-full); + transition: 100ms background-color; + } -input[type="range"]::-moz-range-track { - width: 100%; - height: calc(var(--selector-size) / 4); - background-color: var(--track-color); - border-radius: var(--radius-full); - transition: 100ms background-color; -} + input[type="range"]::-moz-range-track { + width: 100%; + height: calc(var(--selector-size) / 4); + background-color: var(--track-color); + border-radius: var(--radius-full); + transition: 100ms background-color; + } -input[type="range"]::-webkit-slider-thumb { - -webkit-appearance: none; - appearance: none; - width: var(--selector-size); - height: var(--selector-size); - margin-top: calc((calc(var(--selector-size) / 4) - var(--selector-size)) / 2); - background-color: var(--thumb-color); - border: 2px solid var(--color-bg); - border-radius: var(--radius-full); - cursor: pointer; - transition: 100ms background-color; -} + input[type="range"]::-webkit-slider-thumb { + -webkit-appearance: none; + appearance: none; + width: var(--selector-size); + height: var(--selector-size); + margin-top: calc( + (calc(var(--selector-size) / 4) - var(--selector-size)) / + 2 + ); + background-color: var(--thumb-color); + border: 2px solid var(--color-bg); + border-radius: var(--radius-full); + cursor: pointer; + transition: 100ms background-color; + } -input[type="range"]::-moz-range-thumb { - -webkit-appearance: none; - appearance: none; - width: var(--selector-size); - height: var(--selector-size); - margin-top: calc((calc(var(--selector-size) / 4) - var(--selector-size)) / 2); - background-color: var(--thumb-color); - border: 2px solid var(--color-bg); - border-radius: var(--radius-full); - cursor: pointer; - transition: 100ms background-color; -} + input[type="range"]::-moz-range-thumb { + -webkit-appearance: none; + appearance: none; + width: var(--selector-size); + height: var(--selector-size); + margin-top: calc( + (calc(var(--selector-size) / 4) - var(--selector-size)) / + 2 + ); + background-color: var(--thumb-color); + border: 2px solid var(--color-bg); + border-radius: var(--radius-full); + cursor: pointer; + transition: 100ms background-color; + } -progress { - -webkit-appearance: none; - -moz-appearance: none; - appearance: none; - display: inline-block; - width: 100%; - height: var(--selector-size); - overflow: hidden; - border: none; - border-radius: var(--radius-full); - background-color: var(--color-bg-high); - color: var(--color-text-accent); - vertical-align: baseline; -} + progress { + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; + display: inline-block; + width: 100%; + height: var(--selector-size); + overflow: hidden; + border: none; + border-radius: var(--radius-full); + background-color: var(--color-bg-high); + color: var(--color-text-accent); + vertical-align: baseline; + } -progress::-webkit-progress-bar { - border-radius: var(--radius-full); - background: 0 0; -} + progress::-webkit-progress-bar { + border-radius: var(--radius-full); + background: 0 0; + } -progress::-moz-progress-bar { - background-color: var(--color-text-accent); -} + progress::-moz-progress-bar { + background-color: var(--color-text-accent); + } -progress[value]::-webkit-progress-value { - background-color: var(--color-text-accent); - transition: inline-size 0.2s ease; -} + progress[value]::-webkit-progress-value { + background-color: var(--color-text-accent); + transition: inline-size 0.2s ease; + } -td > input[type="checkbox"] { - vertical-align: middle; -} + td > input[type="checkbox"] { + vertical-align: middle; + } -hr { - border: 1px solid var(--color-bg-high); -} + hr { + border: 1px solid var(--color-bg-high); + } -abbr:not([title]) { - text-decoration: none; -} + abbr:not([title]) { + text-decoration: none; + } -abbr[title] { - cursor: help; -} + abbr[title] { + cursor: help; + } -.article > p { - padding-block: var(--s-3); -} + .article > p { + padding-block: var(--s-3); + } -.article img { - height: auto; -} + .article img { + height: auto; + } -/* Hack to deal with Safari bug when the image is loading. See: https://stackoverflow.com/a/73466877 */ -@media not all and (min-resolution: 0.001dpcm) { - img[loading="lazy"] { - clip-path: inset(0.5px); + /* Hack to deal with Safari bug when the image is loading. See: https://stackoverflow.com/a/73466877 */ + @media not all and (min-resolution: 0.001dpcm) { + img[loading="lazy"] { + clip-path: inset(0.5px); + } } } diff --git a/app/styles/flags.css b/app/styles/flags.css index ef5a20fae..be38142ee 100644 --- a/app/styles/flags.css +++ b/app/styles/flags.css @@ -1,1008 +1,1010 @@ -.twf { - display: inline-block; - min-width: 2.5rem; - max-width: 2.5rem; - min-height: 2.5rem; - max-height: 2.5rem; - vertical-align: -0.25em; -} +@layer base { + .twf { + display: inline-block; + min-width: 2.5rem; + max-width: 2.5rem; + min-height: 2.5rem; + max-height: 2.5rem; + vertical-align: -0.25em; + } + + .twf-s { + min-width: 1em; + max-width: 1em; + min-height: 1em; + max-height: 1em; + vertical-align: -0.1em; + } + + .twf-af { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1e6-1f1eb.svg"); + } + + .twf-ax { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1e6-1f1fd.svg"); + } + + .twf-al { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1e6-1f1f1.svg"); + } + + .twf-dz { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1e9-1f1ff.svg"); + } + + .twf-as { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1e6-1f1f8.svg"); + } + + .twf-ad { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1e6-1f1e9.svg"); + } + + .twf-ao { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1e6-1f1f4.svg"); + } + + .twf-ai { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1e6-1f1ee.svg"); + } + + .twf-aq { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1e6-1f1f6.svg"); + } + + .twf-ag { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1e6-1f1ec.svg"); + } + + .twf-ar { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1e6-1f1f7.svg"); + } + + .twf-am { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1e6-1f1f2.svg"); + } + + .twf-aw { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1e6-1f1fc.svg"); + } + + .twf-au { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1e6-1f1fa.svg"); + } + + .twf-at { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1e6-1f1f9.svg"); + } + + .twf-az { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1e6-1f1ff.svg"); + } + + .twf-bs { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1e7-1f1f8.svg"); + } + + .twf-bh { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1e7-1f1ed.svg"); + } + + .twf-bd { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1e7-1f1e9.svg"); + } + + .twf-bb { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1e7-1f1e7.svg"); + } + + .twf-by { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1e7-1f1fe.svg"); + } + + .twf-be { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1e7-1f1ea.svg"); + } + + .twf-bz { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1e7-1f1ff.svg"); + } -.twf-s { - min-width: 1em; - max-width: 1em; - min-height: 1em; - max-height: 1em; - vertical-align: -0.1em; -} + .twf-bj { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1e7-1f1ef.svg"); + } -.twf-af { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1e6-1f1eb.svg"); -} + .twf-bm { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1e7-1f1f2.svg"); + } -.twf-ax { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1e6-1f1fd.svg"); -} + .twf-bt { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1e7-1f1f9.svg"); + } -.twf-al { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1e6-1f1f1.svg"); -} + .twf-bo { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1e7-1f1f4.svg"); + } -.twf-dz { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1e9-1f1ff.svg"); -} + .twf-ba { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1e7-1f1e6.svg"); + } -.twf-as { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1e6-1f1f8.svg"); -} + .twf-bw { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1e7-1f1fc.svg"); + } -.twf-ad { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1e6-1f1e9.svg"); -} + .twf-bv { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1e7-1f1fb.svg"); + } -.twf-ao { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1e6-1f1f4.svg"); -} + .twf-br { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1e7-1f1f7.svg"); + } -.twf-ai { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1e6-1f1ee.svg"); -} + .twf-io { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1ee-1f1f4.svg"); + } -.twf-aq { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1e6-1f1f6.svg"); -} + .twf-bn { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1e7-1f1f3.svg"); + } -.twf-ag { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1e6-1f1ec.svg"); -} + .twf-bg { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1e7-1f1ec.svg"); + } -.twf-ar { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1e6-1f1f7.svg"); -} + .twf-bf { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1e7-1f1eb.svg"); + } -.twf-am { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1e6-1f1f2.svg"); -} + .twf-bi { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1e7-1f1ee.svg"); + } -.twf-aw { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1e6-1f1fc.svg"); -} + .twf-kh { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f0-1f1ed.svg"); + } -.twf-au { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1e6-1f1fa.svg"); -} + .twf-cm { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1e8-1f1f2.svg"); + } -.twf-at { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1e6-1f1f9.svg"); -} + .twf-ca { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1e8-1f1e6.svg"); + } -.twf-az { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1e6-1f1ff.svg"); -} + .twf-cv { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1e8-1f1fb.svg"); + } -.twf-bs { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1e7-1f1f8.svg"); -} + .twf-ky { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f0-1f1fe.svg"); + } -.twf-bh { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1e7-1f1ed.svg"); -} + .twf-cf { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1e8-1f1eb.svg"); + } -.twf-bd { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1e7-1f1e9.svg"); -} + .twf-td { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f9-1f1e9.svg"); + } -.twf-bb { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1e7-1f1e7.svg"); -} + .twf-cl { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1e8-1f1f1.svg"); + } -.twf-by { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1e7-1f1fe.svg"); -} + .twf-cn { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1e8-1f1f3.svg"); + } -.twf-be { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1e7-1f1ea.svg"); -} + .twf-cx { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1e8-1f1fd.svg"); + } -.twf-bz { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1e7-1f1ff.svg"); -} + .twf-cc { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1e8-1f1e8.svg"); + } -.twf-bj { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1e7-1f1ef.svg"); -} + .twf-co { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1e8-1f1f4.svg"); + } -.twf-bm { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1e7-1f1f2.svg"); -} + .twf-km { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f0-1f1f2.svg"); + } -.twf-bt { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1e7-1f1f9.svg"); -} + .twf-cg { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1e8-1f1ec.svg"); + } -.twf-bo { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1e7-1f1f4.svg"); -} + .twf-cd { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1e8-1f1e9.svg"); + } -.twf-ba { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1e7-1f1e6.svg"); -} + .twf-ck { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1e8-1f1f0.svg"); + } -.twf-bw { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1e7-1f1fc.svg"); -} + .twf-cr { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1e8-1f1f7.svg"); + } -.twf-bv { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1e7-1f1fb.svg"); -} + .twf-ci { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1e8-1f1ee.svg"); + } -.twf-br { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1e7-1f1f7.svg"); -} + .twf-hr { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1ed-1f1f7.svg"); + } -.twf-io { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1ee-1f1f4.svg"); -} + .twf-cu { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1e8-1f1fa.svg"); + } -.twf-bn { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1e7-1f1f3.svg"); -} + .twf-cy { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1e8-1f1fe.svg"); + } -.twf-bg { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1e7-1f1ec.svg"); -} + .twf-cz { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1e8-1f1ff.svg"); + } -.twf-bf { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1e7-1f1eb.svg"); -} + .twf-dk { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1e9-1f1f0.svg"); + } -.twf-bi { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1e7-1f1ee.svg"); -} + .twf-dj { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1e9-1f1ef.svg"); + } -.twf-kh { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f0-1f1ed.svg"); -} + .twf-dm { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1e9-1f1f2.svg"); + } -.twf-cm { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1e8-1f1f2.svg"); -} + .twf-do { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1e9-1f1f4.svg"); + } -.twf-ca { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1e8-1f1e6.svg"); -} + .twf-ec { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1ea-1f1e8.svg"); + } -.twf-cv { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1e8-1f1fb.svg"); -} + .twf-eg { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1ea-1f1ec.svg"); + } -.twf-ky { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f0-1f1fe.svg"); -} + .twf-sv { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f8-1f1fb.svg"); + } -.twf-cf { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1e8-1f1eb.svg"); -} + .twf-gq { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1ec-1f1f6.svg"); + } -.twf-td { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f9-1f1e9.svg"); -} + .twf-er { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1ea-1f1f7.svg"); + } -.twf-cl { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1e8-1f1f1.svg"); -} + .twf-ee { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1ea-1f1ea.svg"); + } -.twf-cn { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1e8-1f1f3.svg"); -} + .twf-et { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1ea-1f1f9.svg"); + } -.twf-cx { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1e8-1f1fd.svg"); -} + .twf-fk { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1eb-1f1f0.svg"); + } -.twf-cc { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1e8-1f1e8.svg"); -} + .twf-fo { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1eb-1f1f4.svg"); + } -.twf-co { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1e8-1f1f4.svg"); -} + .twf-fj { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1eb-1f1ef.svg"); + } -.twf-km { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f0-1f1f2.svg"); -} + .twf-fi { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1eb-1f1ee.svg"); + } -.twf-cg { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1e8-1f1ec.svg"); -} + .twf-fr { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1eb-1f1f7.svg"); + } -.twf-cd { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1e8-1f1e9.svg"); -} + .twf-gf { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1ec-1f1eb.svg"); + } -.twf-ck { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1e8-1f1f0.svg"); -} + .twf-pf { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f5-1f1eb.svg"); + } -.twf-cr { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1e8-1f1f7.svg"); -} + .twf-tf { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f9-1f1eb.svg"); + } -.twf-ci { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1e8-1f1ee.svg"); -} + .twf-ga { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1ec-1f1e6.svg"); + } -.twf-hr { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1ed-1f1f7.svg"); -} + .twf-gm { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1ec-1f1f2.svg"); + } -.twf-cu { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1e8-1f1fa.svg"); -} + .twf-ge { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1ec-1f1ea.svg"); + } -.twf-cy { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1e8-1f1fe.svg"); -} + .twf-de { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1e9-1f1ea.svg"); + } -.twf-cz { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1e8-1f1ff.svg"); -} + .twf-gh { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1ec-1f1ed.svg"); + } -.twf-dk { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1e9-1f1f0.svg"); -} + .twf-gi { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1ec-1f1ee.svg"); + } -.twf-dj { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1e9-1f1ef.svg"); -} + .twf-gr { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1ec-1f1f7.svg"); + } -.twf-dm { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1e9-1f1f2.svg"); -} + .twf-gl { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1ec-1f1f1.svg"); + } -.twf-do { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1e9-1f1f4.svg"); -} + .twf-gd { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1ec-1f1e9.svg"); + } -.twf-ec { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1ea-1f1e8.svg"); -} + .twf-gp { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1ec-1f1f5.svg"); + } -.twf-eg { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1ea-1f1ec.svg"); -} + .twf-gu { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1ec-1f1fa.svg"); + } -.twf-sv { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f8-1f1fb.svg"); -} + .twf-gt { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1ec-1f1f9.svg"); + } -.twf-gq { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1ec-1f1f6.svg"); -} + .twf-gg { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1ec-1f1ec.svg"); + } -.twf-er { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1ea-1f1f7.svg"); -} + .twf-gn { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1ec-1f1f3.svg"); + } -.twf-ee { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1ea-1f1ea.svg"); -} + .twf-gw { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1ec-1f1fc.svg"); + } -.twf-et { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1ea-1f1f9.svg"); -} + .twf-gy { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1ec-1f1fe.svg"); + } -.twf-fk { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1eb-1f1f0.svg"); -} + .twf-ht { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1ed-1f1f9.svg"); + } -.twf-fo { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1eb-1f1f4.svg"); -} + .twf-hm { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1ed-1f1f2.svg"); + } -.twf-fj { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1eb-1f1ef.svg"); -} + .twf-va { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1fb-1f1e6.svg"); + } -.twf-fi { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1eb-1f1ee.svg"); -} + .twf-hn { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1ed-1f1f3.svg"); + } -.twf-fr { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1eb-1f1f7.svg"); -} + .twf-hk { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1ed-1f1f0.svg"); + } -.twf-gf { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1ec-1f1eb.svg"); -} + .twf-hu { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1ed-1f1fa.svg"); + } -.twf-pf { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f5-1f1eb.svg"); -} + .twf-is { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1ee-1f1f8.svg"); + } -.twf-tf { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f9-1f1eb.svg"); -} + .twf-in { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1ee-1f1f3.svg"); + } -.twf-ga { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1ec-1f1e6.svg"); -} + .twf-id { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1ee-1f1e9.svg"); + } -.twf-gm { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1ec-1f1f2.svg"); -} + .twf-ir { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1ee-1f1f7.svg"); + } -.twf-ge { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1ec-1f1ea.svg"); -} + .twf-iq { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1ee-1f1f6.svg"); + } -.twf-de { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1e9-1f1ea.svg"); -} + .twf-ie { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1ee-1f1ea.svg"); + } -.twf-gh { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1ec-1f1ed.svg"); -} + .twf-im { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1ee-1f1f2.svg"); + } -.twf-gi { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1ec-1f1ee.svg"); -} + .twf-il { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1ee-1f1f1.svg"); + } -.twf-gr { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1ec-1f1f7.svg"); -} + .twf-it { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1ee-1f1f9.svg"); + } -.twf-gl { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1ec-1f1f1.svg"); -} + .twf-jm { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1ef-1f1f2.svg"); + } -.twf-gd { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1ec-1f1e9.svg"); -} + .twf-jp { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1ef-1f1f5.svg"); + } -.twf-gp { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1ec-1f1f5.svg"); -} + .twf-je { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1ef-1f1ea.svg"); + } -.twf-gu { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1ec-1f1fa.svg"); -} + .twf-jo { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1ef-1f1f4.svg"); + } -.twf-gt { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1ec-1f1f9.svg"); -} + .twf-kz { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f0-1f1ff.svg"); + } -.twf-gg { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1ec-1f1ec.svg"); -} + .twf-ke { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f0-1f1ea.svg"); + } -.twf-gn { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1ec-1f1f3.svg"); -} + .twf-ki { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f0-1f1ee.svg"); + } -.twf-gw { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1ec-1f1fc.svg"); -} + .twf-kp { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f0-1f1f5.svg"); + } -.twf-gy { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1ec-1f1fe.svg"); -} + .twf-kr { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f0-1f1f7.svg"); + } -.twf-ht { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1ed-1f1f9.svg"); -} + .twf-kw { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f0-1f1fc.svg"); + } -.twf-hm { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1ed-1f1f2.svg"); -} + .twf-kg { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f0-1f1ec.svg"); + } -.twf-va { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1fb-1f1e6.svg"); -} + .twf-la { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f1-1f1e6.svg"); + } -.twf-hn { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1ed-1f1f3.svg"); -} + .twf-lv { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f1-1f1fb.svg"); + } -.twf-hk { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1ed-1f1f0.svg"); -} + .twf-lb { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f1-1f1e7.svg"); + } -.twf-hu { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1ed-1f1fa.svg"); -} + .twf-ls { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f1-1f1f8.svg"); + } -.twf-is { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1ee-1f1f8.svg"); -} + .twf-lr { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f1-1f1f7.svg"); + } -.twf-in { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1ee-1f1f3.svg"); -} + .twf-ly { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f1-1f1fe.svg"); + } -.twf-id { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1ee-1f1e9.svg"); -} + .twf-li { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f1-1f1ee.svg"); + } -.twf-ir { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1ee-1f1f7.svg"); -} + .twf-lt { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f1-1f1f9.svg"); + } -.twf-iq { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1ee-1f1f6.svg"); -} + .twf-lu { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f1-1f1fa.svg"); + } -.twf-ie { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1ee-1f1ea.svg"); -} + .twf-mo { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f2-1f1f4.svg"); + } -.twf-im { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1ee-1f1f2.svg"); -} + .twf-mk { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f2-1f1f0.svg"); + } -.twf-il { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1ee-1f1f1.svg"); -} + .twf-mg { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f2-1f1ec.svg"); + } -.twf-it { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1ee-1f1f9.svg"); -} + .twf-mw { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f2-1f1fc.svg"); + } -.twf-jm { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1ef-1f1f2.svg"); -} + .twf-my { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f2-1f1fe.svg"); + } -.twf-jp { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1ef-1f1f5.svg"); -} + .twf-mv { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f2-1f1fb.svg"); + } -.twf-je { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1ef-1f1ea.svg"); -} + .twf-ml { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f2-1f1f1.svg"); + } -.twf-jo { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1ef-1f1f4.svg"); -} + .twf-mt { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f2-1f1f9.svg"); + } -.twf-kz { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f0-1f1ff.svg"); -} + .twf-mh { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f2-1f1ed.svg"); + } -.twf-ke { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f0-1f1ea.svg"); -} + .twf-mq { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f2-1f1f6.svg"); + } -.twf-ki { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f0-1f1ee.svg"); -} + .twf-mr { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f2-1f1f7.svg"); + } -.twf-kp { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f0-1f1f5.svg"); -} + .twf-mu { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f2-1f1fa.svg"); + } -.twf-kr { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f0-1f1f7.svg"); -} + .twf-yt { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1fe-1f1f9.svg"); + } -.twf-kw { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f0-1f1fc.svg"); -} + .twf-mx { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f2-1f1fd.svg"); + } -.twf-kg { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f0-1f1ec.svg"); -} + .twf-fm { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1eb-1f1f2.svg"); + } -.twf-la { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f1-1f1e6.svg"); -} + .twf-md { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f2-1f1e9.svg"); + } -.twf-lv { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f1-1f1fb.svg"); -} + .twf-mc { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f2-1f1e8.svg"); + } -.twf-lb { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f1-1f1e7.svg"); -} + .twf-mn { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f2-1f1f3.svg"); + } -.twf-ls { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f1-1f1f8.svg"); -} + .twf-ms { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f2-1f1f8.svg"); + } -.twf-lr { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f1-1f1f7.svg"); -} + .twf-ma { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f2-1f1e6.svg"); + } -.twf-ly { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f1-1f1fe.svg"); -} + .twf-mz { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f2-1f1ff.svg"); + } -.twf-li { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f1-1f1ee.svg"); -} + .twf-mm { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f2-1f1f2.svg"); + } -.twf-lt { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f1-1f1f9.svg"); -} + .twf-na { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f3-1f1e6.svg"); + } -.twf-lu { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f1-1f1fa.svg"); -} + .twf-nr { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f3-1f1f7.svg"); + } -.twf-mo { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f2-1f1f4.svg"); -} + .twf-np { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f3-1f1f5.svg"); + } -.twf-mk { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f2-1f1f0.svg"); -} + .twf-nl { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f3-1f1f1.svg"); + } -.twf-mg { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f2-1f1ec.svg"); -} + .twf-an { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1e6-1f1f3.svg"); + } -.twf-mw { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f2-1f1fc.svg"); -} + .twf-nc { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f3-1f1e8.svg"); + } -.twf-my { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f2-1f1fe.svg"); -} + .twf-nz { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f3-1f1ff.svg"); + } -.twf-mv { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f2-1f1fb.svg"); -} + .twf-ni { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f3-1f1ee.svg"); + } -.twf-ml { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f2-1f1f1.svg"); -} + .twf-ne { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f3-1f1ea.svg"); + } -.twf-mt { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f2-1f1f9.svg"); -} - -.twf-mh { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f2-1f1ed.svg"); -} - -.twf-mq { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f2-1f1f6.svg"); -} - -.twf-mr { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f2-1f1f7.svg"); -} - -.twf-mu { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f2-1f1fa.svg"); -} - -.twf-yt { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1fe-1f1f9.svg"); -} - -.twf-mx { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f2-1f1fd.svg"); -} - -.twf-fm { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1eb-1f1f2.svg"); -} - -.twf-md { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f2-1f1e9.svg"); -} - -.twf-mc { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f2-1f1e8.svg"); -} - -.twf-mn { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f2-1f1f3.svg"); -} - -.twf-ms { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f2-1f1f8.svg"); -} - -.twf-ma { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f2-1f1e6.svg"); -} - -.twf-mz { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f2-1f1ff.svg"); -} - -.twf-mm { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f2-1f1f2.svg"); -} - -.twf-na { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f3-1f1e6.svg"); -} - -.twf-nr { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f3-1f1f7.svg"); -} - -.twf-np { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f3-1f1f5.svg"); -} + .twf-ng { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f3-1f1ec.svg"); + } -.twf-nl { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f3-1f1f1.svg"); -} + .twf-nu { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f3-1f1fa.svg"); + } -.twf-an { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1e6-1f1f3.svg"); -} - -.twf-nc { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f3-1f1e8.svg"); -} - -.twf-nz { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f3-1f1ff.svg"); -} - -.twf-ni { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f3-1f1ee.svg"); -} - -.twf-ne { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f3-1f1ea.svg"); -} - -.twf-ng { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f3-1f1ec.svg"); -} - -.twf-nu { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f3-1f1fa.svg"); -} - -.twf-nf { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f3-1f1eb.svg"); -} + .twf-nf { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f3-1f1eb.svg"); + } -.twf-mp { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f2-1f1f5.svg"); -} + .twf-mp { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f2-1f1f5.svg"); + } -.twf-no { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f3-1f1f4.svg"); -} + .twf-no { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f3-1f1f4.svg"); + } -.twf-om { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f4-1f1f2.svg"); -} + .twf-om { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f4-1f1f2.svg"); + } -.twf-pk { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f5-1f1f0.svg"); -} + .twf-pk { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f5-1f1f0.svg"); + } -.twf-pw { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f5-1f1fc.svg"); -} + .twf-pw { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f5-1f1fc.svg"); + } -.twf-ps { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f5-1f1f8.svg"); -} + .twf-ps { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f5-1f1f8.svg"); + } -.twf-pa { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f5-1f1e6.svg"); -} + .twf-pa { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f5-1f1e6.svg"); + } -.twf-pg { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f5-1f1ec.svg"); -} + .twf-pg { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f5-1f1ec.svg"); + } -.twf-py { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f5-1f1fe.svg"); -} + .twf-py { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f5-1f1fe.svg"); + } -.twf-pe { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f5-1f1ea.svg"); -} + .twf-pe { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f5-1f1ea.svg"); + } -.twf-ph { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f5-1f1ed.svg"); -} + .twf-ph { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f5-1f1ed.svg"); + } -.twf-pn { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f5-1f1f3.svg"); -} + .twf-pn { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f5-1f1f3.svg"); + } -.twf-pl { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f5-1f1f1.svg"); -} + .twf-pl { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f5-1f1f1.svg"); + } -.twf-pt { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f5-1f1f9.svg"); -} + .twf-pt { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f5-1f1f9.svg"); + } -.twf-pr { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f5-1f1f7.svg"); -} + .twf-pr { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f5-1f1f7.svg"); + } -.twf-qa { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f6-1f1e6.svg"); -} + .twf-qa { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f6-1f1e6.svg"); + } -.twf-re { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f7-1f1ea.svg"); -} + .twf-re { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f7-1f1ea.svg"); + } -.twf-ro { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f7-1f1f4.svg"); -} + .twf-ro { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f7-1f1f4.svg"); + } -.twf-rs { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f7-1f1f8.svg"); -} + .twf-rs { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f7-1f1f8.svg"); + } -.twf-ru { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f7-1f1fa.svg"); -} + .twf-ru { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f7-1f1fa.svg"); + } -.twf-rw { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f7-1f1fc.svg"); -} + .twf-rw { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f7-1f1fc.svg"); + } -.twf-sh { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f8-1f1ed.svg"); -} + .twf-sh { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f8-1f1ed.svg"); + } -.twf-kn { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f0-1f1f3.svg"); -} + .twf-kn { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f0-1f1f3.svg"); + } -.twf-lc { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f1-1f1e8.svg"); -} + .twf-lc { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f1-1f1e8.svg"); + } -.twf-pm { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f5-1f1f2.svg"); -} + .twf-pm { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f5-1f1f2.svg"); + } -.twf-vc { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1fb-1f1e8.svg"); -} + .twf-vc { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1fb-1f1e8.svg"); + } -.twf-ws { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1fc-1f1f8.svg"); -} + .twf-ws { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1fc-1f1f8.svg"); + } -.twf-sm { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f8-1f1f2.svg"); -} + .twf-sm { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f8-1f1f2.svg"); + } -.twf-st { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f8-1f1f9.svg"); -} + .twf-st { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f8-1f1f9.svg"); + } -.twf-sa { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f8-1f1e6.svg"); -} + .twf-sa { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f8-1f1e6.svg"); + } -.twf-sn { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f8-1f1f3.svg"); -} + .twf-sn { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f8-1f1f3.svg"); + } -.twf-cs { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1e8-1f1f8.svg"); -} + .twf-cs { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1e8-1f1f8.svg"); + } -.twf-sc { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f8-1f1e8.svg"); -} + .twf-sc { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f8-1f1e8.svg"); + } -.twf-sl { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f8-1f1f1.svg"); -} + .twf-sl { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f8-1f1f1.svg"); + } -.twf-sg { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f8-1f1ec.svg"); -} + .twf-sg { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f8-1f1ec.svg"); + } -.twf-sk { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f8-1f1f0.svg"); -} + .twf-sk { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f8-1f1f0.svg"); + } -.twf-si { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f8-1f1ee.svg"); -} + .twf-si { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f8-1f1ee.svg"); + } -.twf-sb { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f8-1f1e7.svg"); -} + .twf-sb { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f8-1f1e7.svg"); + } -.twf-so { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f8-1f1f4.svg"); -} + .twf-so { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f8-1f1f4.svg"); + } -.twf-za { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1ff-1f1e6.svg"); -} + .twf-za { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1ff-1f1e6.svg"); + } -.twf-gs { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1ec-1f1f8.svg"); -} + .twf-gs { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1ec-1f1f8.svg"); + } -.twf-es { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1ea-1f1f8.svg"); -} + .twf-es { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1ea-1f1f8.svg"); + } -.twf-lk { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f1-1f1f0.svg"); -} + .twf-lk { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f1-1f1f0.svg"); + } -.twf-sd { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f8-1f1e9.svg"); -} + .twf-sd { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f8-1f1e9.svg"); + } -.twf-sr { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f8-1f1f7.svg"); -} + .twf-sr { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f8-1f1f7.svg"); + } -.twf-sj { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f8-1f1ef.svg"); -} + .twf-sj { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f8-1f1ef.svg"); + } -.twf-sz { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f8-1f1ff.svg"); -} + .twf-sz { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f8-1f1ff.svg"); + } -.twf-se { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f8-1f1ea.svg"); -} + .twf-se { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f8-1f1ea.svg"); + } -.twf-ch { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1e8-1f1ed.svg"); -} + .twf-ch { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1e8-1f1ed.svg"); + } -.twf-sy { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f8-1f1fe.svg"); -} + .twf-sy { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f8-1f1fe.svg"); + } -.twf-tw { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f9-1f1fc.svg"); -} + .twf-tw { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f9-1f1fc.svg"); + } -.twf-tj { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f9-1f1ef.svg"); -} + .twf-tj { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f9-1f1ef.svg"); + } -.twf-tz { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f9-1f1ff.svg"); -} + .twf-tz { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f9-1f1ff.svg"); + } -.twf-th { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f9-1f1ed.svg"); -} + .twf-th { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f9-1f1ed.svg"); + } -.twf-tl { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f9-1f1f1.svg"); -} + .twf-tl { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f9-1f1f1.svg"); + } -.twf-tg { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f9-1f1ec.svg"); -} + .twf-tg { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f9-1f1ec.svg"); + } -.twf-tk { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f9-1f1f0.svg"); -} + .twf-tk { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f9-1f1f0.svg"); + } -.twf-to { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f9-1f1f4.svg"); -} + .twf-to { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f9-1f1f4.svg"); + } -.twf-tt { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f9-1f1f9.svg"); -} + .twf-tt { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f9-1f1f9.svg"); + } -.twf-tn { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f9-1f1f3.svg"); -} + .twf-tn { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f9-1f1f3.svg"); + } -.twf-tr { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f9-1f1f7.svg"); -} + .twf-tr { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f9-1f1f7.svg"); + } -.twf-tm { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f9-1f1f2.svg"); -} + .twf-tm { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f9-1f1f2.svg"); + } -.twf-tc { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f9-1f1e8.svg"); -} + .twf-tc { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f9-1f1e8.svg"); + } -.twf-tv { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f9-1f1fb.svg"); -} + .twf-tv { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1f9-1f1fb.svg"); + } -.twf-ug { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1fa-1f1ec.svg"); -} + .twf-ug { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1fa-1f1ec.svg"); + } -.twf-ua { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1fa-1f1e6.svg"); -} + .twf-ua { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1fa-1f1e6.svg"); + } -.twf-ae { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1e6-1f1ea.svg"); -} + .twf-ae { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1e6-1f1ea.svg"); + } -.twf-gb { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1ec-1f1e7.svg"); -} + .twf-gb { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1ec-1f1e7.svg"); + } -.twf-us { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1fa-1f1f8.svg"); -} + .twf-us { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1fa-1f1f8.svg"); + } -.twf-um { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1fa-1f1f2.svg"); -} + .twf-um { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1fa-1f1f2.svg"); + } -.twf-uy { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1fa-1f1fe.svg"); -} + .twf-uy { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1fa-1f1fe.svg"); + } -.twf-uz { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1fa-1f1ff.svg"); -} + .twf-uz { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1fa-1f1ff.svg"); + } -.twf-vu { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1fb-1f1fa.svg"); -} + .twf-vu { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1fb-1f1fa.svg"); + } -.twf-ve { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1fb-1f1ea.svg"); -} + .twf-ve { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1fb-1f1ea.svg"); + } -.twf-vn { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1fb-1f1f3.svg"); -} + .twf-vn { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1fb-1f1f3.svg"); + } -.twf-vg { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1fb-1f1ec.svg"); -} + .twf-vg { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1fb-1f1ec.svg"); + } -.twf-vi { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1fb-1f1ee.svg"); -} + .twf-vi { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1fb-1f1ee.svg"); + } -.twf-wf { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1fc-1f1eb.svg"); -} + .twf-wf { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1fc-1f1eb.svg"); + } -.twf-eh { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1ea-1f1ed.svg"); -} + .twf-eh { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1ea-1f1ed.svg"); + } -.twf-ye { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1fe-1f1ea.svg"); -} + .twf-ye { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1fe-1f1ea.svg"); + } -.twf-zm { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1ff-1f1f2.svg"); -} + .twf-zm { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1ff-1f1f2.svg"); + } -.twf-zw { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1ff-1f1fc.svg"); -} + .twf-zw { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1ff-1f1fc.svg"); + } -.twf-gb-wls { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f3f4-e0067-e0062-e0077-e006c-e0073-e007f.svg"); -} + .twf-gb-wls { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f3f4-e0067-e0062-e0077-e006c-e0073-e007f.svg"); + } -.twf-gb-eng { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f3f4-e0067-e0062-e0065-e006e-e0067-e007f.svg"); -} + .twf-gb-eng { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f3f4-e0067-e0062-e0065-e006e-e0067-e007f.svg"); + } -.twf-gb-sct { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f3f4-e0067-e0062-e0073-e0063-e0074-e007f.svg"); -} + .twf-gb-sct { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f3f4-e0067-e0062-e0073-e0063-e0074-e007f.svg"); + } -.twf-gb-nir { - background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1ec-1f1e7.svg"); + .twf-gb-nir { + background-image: url("https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg/1f1ec-1f1e7.svg"); + } } diff --git a/app/styles/normalize.css b/app/styles/normalize.css index e72e1e136..8b0b25525 100644 --- a/app/styles/normalize.css +++ b/app/styles/normalize.css @@ -1,214 +1,217 @@ -/*! modern-normalize v3.0.1 | MIT License | https://github.com/sindresorhus/modern-normalize */ +@layer reset { + /*! modern-normalize v3.0.1 | MIT License | https://github.com/sindresorhus/modern-normalize */ -/* + /* Document ======== */ -/** + /** Use a better box model (opinionated). */ -*, -::before, -::after { - box-sizing: border-box; -} + *, + ::before, + ::after { + box-sizing: border-box; + } -/** + /** 1. Improve consistency of default fonts in all browsers. (https://github.com/sindresorhus/modern-normalize/issues/3) 2. Correct the line height in all browsers. 3. Prevent adjustments of font size after orientation changes in iOS. 4. Use a more readable tab size (opinionated). */ -html { - font-family: - system-ui, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, - "Apple Color Emoji", "Segoe UI Emoji"; /* 1 */ - line-height: 1.15; /* 2 */ - -webkit-text-size-adjust: 100%; /* 3 */ - tab-size: 4; /* 4 */ -} + html { + font-family: + system-ui, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, + "Apple Color Emoji", "Segoe UI Emoji"; /* 1 */ + line-height: 1.15; /* 2 */ + -webkit-text-size-adjust: 100%; /* 3 */ + tab-size: 4; /* 4 */ + } -/* + /* Sections ======== */ -/** + /** Remove the margin in all browsers. */ -body { - margin: 0; -} + body { + margin: 0; + } -/* + /* Text-level semantics ==================== */ -/** + /** Add the correct font weight in Chrome and Safari. */ -b, -strong { - font-weight: bolder; -} + b, + strong { + font-weight: bolder; + } -/** + /** 1. Improve consistency of default fonts in all browsers. (https://github.com/sindresorhus/modern-normalize/issues/3) 2. Correct the odd 'em' font sizing in all browsers. */ -code, -kbd, -samp, -pre { - font-family: - ui-monospace, SFMono-Regular, Consolas, "Liberation Mono", Menlo, monospace; /* 1 */ - font-size: 1em; /* 2 */ -} + code, + kbd, + samp, + pre { + font-family: + ui-monospace, SFMono-Regular, Consolas, "Liberation Mono", Menlo, + monospace; /* 1 */ + font-size: 1em; /* 2 */ + } -/** + /** Add the correct font size in all browsers. */ -small { - font-size: 80%; -} + small { + font-size: 80%; + } -/** + /** Prevent 'sub' and 'sup' elements from affecting the line height in all browsers. */ -sub, -sup { - font-size: 75%; - line-height: 0; - position: relative; - vertical-align: baseline; -} + sub, + sup { + font-size: 75%; + line-height: 0; + position: relative; + vertical-align: baseline; + } -sub { - bottom: -0.25em; -} + sub { + bottom: -0.25em; + } -sup { - top: -0.5em; -} + sup { + top: -0.5em; + } -/* + /* Tabular data ============ */ -/** + /** Correct table border color inheritance in Chrome and Safari. (https://issues.chromium.org/issues/40615503, https://bugs.webkit.org/show_bug.cgi?id=195016) */ -table { - border-color: currentcolor; -} + table { + border-color: currentcolor; + } -/* + /* Forms ===== */ -/** + /** 1. Change the font styles in all browsers. 2. Remove the margin in Firefox and Safari. */ -button, -input, -optgroup, -select, -textarea { - font-family: inherit; /* 1 */ - font-size: 100%; /* 1 */ - line-height: 1.15; /* 1 */ - margin: 0; /* 2 */ -} + button, + input, + optgroup, + select, + textarea { + font-family: inherit; /* 1 */ + font-size: 100%; /* 1 */ + line-height: 1.15; /* 1 */ + margin: 0; /* 2 */ + } -/** + /** Correct the inability to style clickable types in iOS and Safari. */ -button, -[type="button"], -[type="reset"], -[type="submit"] { - appearance: button; - -webkit-appearance: button; -} + button, + [type="button"], + [type="reset"], + [type="submit"] { + appearance: button; + -webkit-appearance: button; + } -/** + /** Remove the padding so developers are not caught out when they zero out 'fieldset' elements in all browsers. */ -legend { - padding: 0; -} + legend { + padding: 0; + } -/** + /** Add the correct vertical alignment in Chrome and Firefox. */ -progress { - vertical-align: baseline; -} + progress { + vertical-align: baseline; + } -/** + /** Correct the cursor style of increment and decrement buttons in Safari. */ -::-webkit-inner-spin-button, -::-webkit-outer-spin-button { - height: auto; -} + ::-webkit-inner-spin-button, + ::-webkit-outer-spin-button { + height: auto; + } -/** + /** 1. Correct the odd appearance in Chrome and Safari. 2. Correct the outline style in Safari. */ -[type="search"] { - appearance: textfield; /* 1 */ - -webkit-appearance: textfield; /* 1 */ - outline-offset: -2px; /* 2 */ -} + [type="search"] { + appearance: textfield; /* 1 */ + -webkit-appearance: textfield; /* 1 */ + outline-offset: -2px; /* 2 */ + } -/** + /** Remove the inner padding in Chrome and Safari on macOS. */ -::-webkit-search-decoration { - -webkit-appearance: none; -} + ::-webkit-search-decoration { + -webkit-appearance: none; + } -/** + /** 1. Correct the inability to style clickable types in iOS and Safari. 2. Change font properties to 'inherit' in Safari. */ -::-webkit-file-upload-button { - -webkit-appearance: button; /* 1 */ - font: inherit; /* 2 */ -} + ::-webkit-file-upload-button { + -webkit-appearance: button; /* 1 */ + font: inherit; /* 2 */ + } -/* + /* Interactive =========== */ -/* + /* Add the correct display in Chrome and Safari. */ -summary { - display: list-item; + summary { + display: list-item; + } } diff --git a/app/styles/utils.css b/app/styles/utils.css index 7c4219ba0..be7d7d939 100644 --- a/app/styles/utils.css +++ b/app/styles/utils.css @@ -1,628 +1,618 @@ -.text-xl { - font-size: var(--font-xl); -} +@layer utilities { + .text-xl { + font-size: var(--font-xl); + } -.text-lg { - font-size: var(--font-lg); -} + .text-lg { + font-size: var(--font-lg); + } -.text-sm { - font-size: var(--font-sm); -} + .text-sm { + font-size: var(--font-sm); + } -.text-md { - font-size: var(--font-md); -} + .text-md { + font-size: var(--font-md); + } -.text-xs { - font-size: var(--font-xs); -} + .text-xs { + font-size: var(--font-xs); + } -.text-xxs { - font-size: var(--font-2xs); -} + .text-xxs { + font-size: var(--font-2xs); + } -.text-xxxs { - font-size: var(--font-2xs); -} + .text-xxxs { + font-size: var(--font-2xs); + } -.text-center { - text-align: center; -} + .text-center { + text-align: center; + } -.text-left { - text-align: left; -} + .text-left { + text-align: left; + } -.text-main-forced { - color: var(--color-text) !important; -} + .text-main-forced { + color: var(--color-text); + } -.text-lighter { - color: var(--color-text-high); -} + .text-lighter { + color: var(--color-text-high); + } -.text-lighter-important { - color: var(--color-text-high) !important; -} + .text-theme-transparent { + color: var(--color-accent-low); + } -.text-theme-transparent { - color: var(--color-accent-low); -} + .text-error { + color: var(--color-error); + } -.text-error { - color: var(--color-error); -} + .text-success { + color: var(--color-success); + } -.text-success { - color: var(--color-success); -} + .text-info { + color: var(--color-info); + } -.text-info { - color: var(--color-info); -} + .text-warning { + color: var(--color-warning); + } -.text-warning { - color: var(--color-warning); -} + .text-theme { + color: var(--color-text-accent); + } -.text-warning-important { - color: var(--color-warning) !important; -} + .text-theme-secondary { + color: var(--color-text-second); + } -.text-theme { - color: var(--color-text-accent); -} + .text-uppercase { + text-transform: uppercase; + } -.text-theme-secondary { - color: var(--color-text-second); -} + .text-capitalize { + text-transform: capitalize; + } -.text-uppercase { - text-transform: uppercase; -} + .underline { + text-decoration: underline; + } -.text-capitalize { - text-transform: capitalize; -} + .color-success { + color: var(--color-success); + } -.underline { - text-decoration: underline; -} + .color-warning { + color: var(--color-warning); + } -.color-success { - color: var(--color-success); -} + .color-error { + color: var(--color-error); + } -.color-warning { - color: var(--color-warning); -} + .color-info { + color: var(--color-info); + } -.color-error { - color: var(--color-error); -} + .bg { + background-color: var(--color-bg); + } -.color-info { - color: var(--color-info); -} + .bg-lighter { + background-color: var(--color-bg-high); + } -.bg { - background-color: var(--color-bg); -} + .bg-transparent { + background-color: transparent; + } -.bg-lighter { - background-color: var(--color-bg-high); -} + .bg-darker-transparent { + background-color: var(--color-bg); + } -.bg-transparent-important { - background-color: transparent !important; -} + .bg-theme-transparent { + background-color: var(--color-accent-low); + } -.bg-darker-transparent { - background-color: var(--color-bg); -} + .rounded { + border-radius: var(--radius-box); + } -.bg-theme-transparent-important { - background-color: var(--color-accent-low) !important; -} + .rounded-sm { + border-radius: var(--radius-field); + } -.rounded { - border-radius: var(--radius-box); -} + .rounded-full { + border-radius: 100%; + } -.rounded-sm { - border-radius: var(--radius-field); -} + .font-body { + font-weight: var(--weight-body); + } -.rounded-full { - border-radius: 100%; -} + .font-semi-bold { + font-weight: var(--weight-semi); + } -.font-body { - font-weight: var(--weight-body); -} + .font-bold { + font-weight: var(--weight-bold); + } -.font-semi-bold { - font-weight: var(--weight-semi); -} + .h-full { + height: 100%; + } -.font-bold { - font-weight: var(--weight-bold); -} + .w-full { + width: 100%; + } -.h-full { - height: 100%; -} + .w-4 { + width: var(--s-4); + } -.w-full { - width: 100%; -} + .w-6 { + width: var(--s-6); + } -.w-full-important { - width: 100% !important; -} + .w-24 { + width: var(--s-24); + } -.w-4 { - width: var(--s-4); -} + .min-w-max { + min-width: max-content; + } -.w-6 { - width: var(--s-6); -} + .w-max { + width: max-content; + } -.w-24 { - width: var(--s-24); -} + .w-min { + width: min-content; + } -.min-w-max { - min-width: max-content; -} + .p-1 { + padding: var(--s-1); + } -.w-max { - width: max-content; -} + .p-1-5 { + padding: var(--s-1-5); + } -.w-min { - width: min-content; -} + .px-4 { + padding-inline: var(--s-4); + } -.p-1 { - padding: var(--s-1); -} + .py-4 { + padding-block: var(--s-4); + } -.p-1-5 { - padding: var(--s-1-5); -} + .pl-0 { + padding-inline-start: 0; + } -.px-4 { - padding-inline: var(--s-4); -} + .pl-4 { + padding-inline-start: var(--s-4); + } -.py-4 { - padding-block: var(--s-4); -} + .px-2 { + padding-inline: var(--s-2); + } -.pl-0 { - padding-inline-start: 0; -} + .pb-4 { + padding-block-end: var(--s-4); + } -.pl-4 { - padding-inline-start: var(--s-4); -} + .pt-0 { + padding-block-start: 0; + } -.px-2 { - padding-inline: var(--s-2); -} + .pt-0-5 { + padding-block-start: var(--s-0-5); + } -.pb-4 { - padding-block-end: var(--s-4); -} + .pt-8 { + padding-block-start: var(--s-8); + } -.pt-0 { - padding-block-start: 0; -} + .m-auto-0 { + margin: auto 0; + } -.pt-0-5-forced { - padding-block-start: var(--s-0-5) !important; -} + .mt-auto { + margin-block-start: auto; + } -.pt-8-forced { - padding-block-start: var(--s-8) !important; -} + .mt-0 { + margin-block-start: 0; + } -.m-auto-0 { - margin: auto 0; -} + .-mt-1px { + margin-block-start: -1px; + } -.mt-auto { - margin-block-start: auto; -} + .mt-1 { + margin-block-start: var(--s-1); + } -.mt-0 { - margin-block-start: 0; -} + .mt-1-5 { + margin-block-start: var(--s-1-5); + } -.-mt-1px { - margin-block-start: -1px; -} + .mt-2 { + margin-block-start: var(--s-2); + } -.mt-1 { - margin-block-start: var(--s-1); -} + .mt-3 { + margin-block-start: var(--s-3); + } -.mt-1-5 { - margin-block-start: var(--s-1-5); -} + .mt-4 { + margin-block-start: var(--s-4); + } -.mt-2 { - margin-block-start: var(--s-2); -} + .mt-6 { + margin-block-start: var(--s-6); + } -.mt-3 { - margin-block-start: var(--s-3); -} + .mt-12 { + margin-block-start: var(--s-12); + } -.mt-4 { - margin-block-start: var(--s-4); -} + .mb-0 { + margin-block-end: 0; + } -.mt-6 { - margin-block-start: var(--s-6); -} + .mb-1 { + margin-block-end: var(--s-1); + } -.mt-12 { - margin-block-start: var(--s-12); -} + .mb-2 { + margin-block-end: var(--s-2); + } -.mb-0 { - margin-block-end: 0; -} + .mb-4 { + margin-block-end: var(--s-4); + } -.mb-1 { - margin-block-end: var(--s-1); -} + .ml-auto { + margin-inline-start: auto; + } -.mb-2 { - margin-block-end: var(--s-2); -} + .ml-1 { + margin-inline-start: var(--s-1); + } -.mb-4 { - margin-block-end: var(--s-4); -} + .ml-2 { + margin-inline-start: var(--s-2); + } -.ml-auto { - margin-inline-start: auto; -} + .ml-2-5 { + margin-inline-start: var(--s-3); + } -.ml-1 { - margin-inline-start: var(--s-1); -} + .ml-4 { + margin-inline-start: var(--s-4); + } -.ml-2 { - margin-inline-start: var(--s-2); -} + .ml-6 { + margin-inline-start: var(--s-6); + } -.ml-2-5 { - margin-inline-start: var(--s-3); -} + .mr-auto { + margin-inline-end: auto; + } -.ml-4 { - margin-inline-start: var(--s-4); -} + .mr-1 { + margin-inline-end: var(--s-1); + } -.ml-6 { - margin-inline-start: var(--s-6); -} + .mr-2 { + margin-inline-end: var(--s-2); + } -.mr-auto { - margin-inline-end: auto; -} + .mr-4 { + margin-inline-end: var(--s-4); + } -.mr-1 { - margin-inline-end: var(--s-1); -} + .mx-auto { + margin-inline: auto; + } -.mr-2 { - margin-inline-end: var(--s-2); -} + .mx-1 { + margin-inline: var(--s-1); + } -.mr-4 { - margin-inline-end: var(--s-4); -} + .mx-2 { + margin-inline: var(--s-2); + } -.mx-auto { - margin-inline: auto; -} + .my-auto { + margin-block: auto; + } -.mx-1 { - margin-inline: var(--s-1); -} + .my-1 { + margin-block: var(--s-1); + } -.mx-2 { - margin-inline: var(--s-2); -} + .my-2 { + margin-block: var(--s-2); + } -.my-auto { - margin-block: auto; -} + .my-3 { + margin-block: var(--s-3); + } -.my-1 { - margin-block: var(--s-1); -} + .my-4 { + margin-block: var(--s-4); + } -.my-2 { - margin-block: var(--s-2); -} + .my-24 { + margin-block: var(--s-24); + } -.my-3 { - margin-block: var(--s-3); -} + .m-0-auto { + margin: 0 auto; + } -.my-4 { - margin-block: var(--s-4); -} + .hidden { + display: none; + } -.my-24 { - margin-block: var(--s-24); -} + .invisible { + visibility: hidden; + } -.m-0-auto { - margin: 0 auto; -} + .whitespace-pre-wrap { + white-space: pre-wrap; + } -.hidden { - display: none; -} + .whitespace-nowrap { + white-space: nowrap; + } -.invisible { - visibility: hidden; -} + .overflow-x-auto { + overflow-x: auto; + } -.whitespace-pre-wrap { - white-space: pre-wrap; -} + .overflow-x-scroll { + overflow-x: scroll; + } -.whitespace-nowrap { - white-space: nowrap; -} + .relative { + position: relative; + } -.overflow-x-auto { - overflow-x: auto; -} + .italic { + font-style: italic; + } -.overflow-x-scroll { - overflow-x: scroll; -} + .contents { + display: contents; + } -.relative { - position: relative; -} + .flex { + display: flex; + } -.italic { - font-style: italic; -} + .items-center { + align-items: center; + } -.contents { - display: contents; -} + .items-start { + align-items: flex-start; + } -.flex { - display: flex; -} + .items-end { + align-items: flex-end; + } -.items-center { - align-items: center; -} + .justify-center { + justify-content: center; + } -.items-start { - align-items: flex-start; -} + .justify-end { + justify-content: flex-end; + } -.items-end { - align-items: flex-end; -} + .justify-between { + justify-content: space-between; + } -.justify-center { - justify-content: center; -} + .justify-evenly { + justify-content: space-evenly; + } -.justify-end { - justify-content: flex-end; -} + .justify-self-end { + justify-self: flex-end; + } -.justify-between { - justify-content: space-between; -} + .justify-self-center { + justify-self: center; + } -.justify-evenly { - justify-content: space-evenly; -} + .self-center { + align-self: center; + } -.justify-self-end { - justify-self: flex-end; -} + .self-start { + align-self: flex-start; + } -.justify-self-center { - justify-self: center; -} + .justify-self-start { + justify-self: flex-start; + } -.self-center { - align-self: center; -} + .flex-wrap { + flex-wrap: wrap; + } -.self-start { - align-self: flex-start; -} + .flex-wrap-reverse { + flex-wrap: wrap-reverse; + } -.justify-self-start { - justify-self: flex-start; -} + .all-unset { + all: unset; + } -.flex-wrap { - flex-wrap: wrap; -} + .focus-text-decoration:focus-visible { + outline: none; + text-decoration: underline; + } -.flex-wrap-reverse { - flex-wrap: wrap-reverse; -} + .label-no-spacing { + --label-margin: 0; + } -.all-unset { - all: unset; -} - -.focus-text-decoration:focus-visible { - outline: none !important; - text-decoration: underline; -} - -.label-no-spacing { - --label-margin: 0; -} - -.mobile-hidden { - display: none; -} - -.desktop-hidden { - display: inherit; -} - -.cursor-pointer { - cursor: pointer; -} - -.opaque { - opacity: 0.6; -} - -.list-none { - list-style: none; -} - -@media screen and (min-width: 480px) { .mobile-hidden { - display: inherit; + display: none; } .desktop-hidden { - display: none; - } -} - -.scrollbar { - @supports not selector(::-webkit-scrollbar) { - scrollbar-width: thin; - scrollbar-color: var(--color-bg-higher) transparent; + display: inherit; } - &::-webkit-scrollbar, - &::-webkit-scrollbar-track { - background-color: transparent; - height: 14px; - width: 14px; + .cursor-pointer { + cursor: pointer; } - &::-webkit-scrollbar-thumb { - background-color: var(--color-base-4); - border-radius: var(--radius-full); - border: 4px solid transparent; - background-clip: content-box; + .opaque { + opacity: 0.6; + } + + .list-none { + list-style: none; + } + + @media screen and (min-width: 480px) { + .mobile-hidden { + display: inherit; + } + + .desktop-hidden { + display: none; + } + } + + .scrollbar { + @supports not selector(::-webkit-scrollbar) { + scrollbar-width: thin; + scrollbar-color: var(--color-bg-higher) transparent; + } + + &::-webkit-scrollbar, + &::-webkit-scrollbar-track { + background-color: transparent; + height: 14px; + width: 14px; + } + + &::-webkit-scrollbar-thumb { + background-color: var(--color-base-4); + border-radius: var(--radius-full); + border: 4px solid transparent; + background-clip: content-box; + } + } + + .stack { + display: flex; + flex-direction: column; + } + + .stack.xxxs { + gap: var(--s-0-5); + } + + .stack.xxs { + gap: var(--s-1); + } + + .stack.xs { + gap: var(--s-1-5); + } + + .stack.sm { + gap: var(--s-2); + } + + .stack.sm-column { + column-gap: var(--s-2); + } + + .stack.sm-plus { + gap: var(--s-3); + } + + .stack.md { + gap: var(--s-4); + } + + .stack.md-plus { + gap: var(--s-6); + } + + .stack.lg { + gap: var(--s-8); + } + + .stack.xs-row { + row-gap: var(--s-1-5); + } + + .stack.lg-row { + row-gap: var(--s-8); + } + + .stack.xl { + gap: var(--s-12); + } + + .stack.xxl { + gap: var(--s-16); + } + + .stack.horizontal { + flex-direction: row; + } + + .flex-same-size { + flex: 1 1 0px; + } + + .small-icon { + width: 1.2rem; + height: 1.2rem; + } + + .small-text { + font-size: var(--font-2xs); + } + + .dotted { + text-decoration-style: dotted; + text-decoration-line: underline; + text-decoration-thickness: 2px; + } + + .summary { + border-radius: var(--radius-box); + background-color: var(--color-bg); + font-size: var(--font-xs); + font-weight: var(--weight-semi); + padding-block: var(--s-1); + padding-inline: var(--s-2); + } + + html[dir="rtl"] .fix-rtl { + transform: rotate(180deg); + } + + .clickable { + cursor: pointer; } } - -.stack { - display: flex; - flex-direction: column; -} - -.stack.xxxs { - gap: var(--s-0-5); -} - -.stack.xxs { - gap: var(--s-1); -} - -.stack.xs { - gap: var(--s-1-5); -} - -.stack.sm { - gap: var(--s-2); -} - -.stack.sm-column { - column-gap: var(--s-2); -} - -.stack.sm-plus { - gap: var(--s-3); -} - -.stack.md { - gap: var(--s-4); -} - -.stack.md-plus { - gap: var(--s-6); -} - -.stack.lg { - gap: var(--s-8); -} - -.stack.xs-row { - row-gap: var(--s-1-5); -} - -.stack.lg-row { - row-gap: var(--s-8); -} - -.stack.xl { - gap: var(--s-12); -} - -.stack.xxl { - gap: var(--s-16); -} - -.stack.horizontal { - flex-direction: row; -} - -.flex-same-size { - flex: 1 1 0px; -} - -.small-icon { - width: 1.2rem; - height: 1.2rem; -} - -.small-text { - font-size: var(--font-2xs) !important; -} - -.dotted { - text-decoration-style: dotted; - text-decoration-line: underline; - text-decoration-thickness: 2px; -} - -.summary { - border-radius: var(--radius-box); - background-color: var(--color-bg); - font-size: var(--font-xs); - font-weight: var(--weight-semi); - padding-block: var(--s-1); - padding-inline: var(--s-2); -} - -html[dir="rtl"] .fix-rtl { - transform: rotate(180deg); -} - -.clickable { - cursor: pointer; -} diff --git a/app/styles/vars.css b/app/styles/vars.css index 5e5fc73b3..191e05f61 100644 --- a/app/styles/vars.css +++ b/app/styles/vars.css @@ -1,6 +1,8 @@ -/* +@layer reset, base, components, utilities; + +/* ⚠️⚠️⚠️ -Make sure to read styles.md before editing colors in this file, +Make sure to read styles.md before editing colors in this file, it contains important information about how the styles work and how to edit them properly ⚠️⚠️⚠️ */ diff --git a/app/utils/urls.ts b/app/utils/urls.ts index f4e451fc7..ebde668c7 100644 --- a/app/utils/urls.ts +++ b/app/utils/urls.ts @@ -120,6 +120,7 @@ export const SENDOUQ_STREAMS_PAGE = "/q/streams"; export const TIERS_PAGE = "/tiers"; export const SUSPENDED_PAGE = "/suspended"; export const LFG_PAGE = "/lfg"; +export const EVENTS_PAGE = "/events"; export const FRIENDS_PAGE = "/friends"; export const SETTINGS_PAGE = "/settings"; export const LUTI_PAGE = "/luti"; diff --git a/e2e/seeds/db-seed-DEFAULT.sqlite3 b/e2e/seeds/db-seed-DEFAULT.sqlite3 index 7c4e4a62a..5224250f2 100644 Binary files a/e2e/seeds/db-seed-DEFAULT.sqlite3 and b/e2e/seeds/db-seed-DEFAULT.sqlite3 differ diff --git a/e2e/seeds/db-seed-NO_SCRIMS.sqlite3 b/e2e/seeds/db-seed-NO_SCRIMS.sqlite3 index 47eb1d87e..ab7c888ad 100644 Binary files a/e2e/seeds/db-seed-NO_SCRIMS.sqlite3 and b/e2e/seeds/db-seed-NO_SCRIMS.sqlite3 differ diff --git a/e2e/seeds/db-seed-NO_SQ_GROUPS.sqlite3 b/e2e/seeds/db-seed-NO_SQ_GROUPS.sqlite3 index 6a18920a9..33db0b481 100644 Binary files a/e2e/seeds/db-seed-NO_SQ_GROUPS.sqlite3 and b/e2e/seeds/db-seed-NO_SQ_GROUPS.sqlite3 differ diff --git a/e2e/seeds/db-seed-NO_TOURNAMENT_TEAMS.sqlite3 b/e2e/seeds/db-seed-NO_TOURNAMENT_TEAMS.sqlite3 index 1738c45bf..8d36e3380 100644 Binary files a/e2e/seeds/db-seed-NO_TOURNAMENT_TEAMS.sqlite3 and b/e2e/seeds/db-seed-NO_TOURNAMENT_TEAMS.sqlite3 differ diff --git a/e2e/seeds/db-seed-NZAP_IN_TEAM.sqlite3 b/e2e/seeds/db-seed-NZAP_IN_TEAM.sqlite3 index dffd9ce06..ed2b68b1d 100644 Binary files a/e2e/seeds/db-seed-NZAP_IN_TEAM.sqlite3 and b/e2e/seeds/db-seed-NZAP_IN_TEAM.sqlite3 differ diff --git a/e2e/seeds/db-seed-REG_OPEN.sqlite3 b/e2e/seeds/db-seed-REG_OPEN.sqlite3 index f727d3b5e..d069bac7a 100644 Binary files a/e2e/seeds/db-seed-REG_OPEN.sqlite3 and b/e2e/seeds/db-seed-REG_OPEN.sqlite3 differ diff --git a/e2e/seeds/db-seed-SMALL_SOS.sqlite3 b/e2e/seeds/db-seed-SMALL_SOS.sqlite3 index d66a27986..f628502b3 100644 Binary files a/e2e/seeds/db-seed-SMALL_SOS.sqlite3 and b/e2e/seeds/db-seed-SMALL_SOS.sqlite3 differ diff --git a/e2e/team.spec.ts b/e2e/team.spec.ts index 5bcd0343a..553319753 100644 --- a/e2e/team.spec.ts +++ b/e2e/team.spec.ts @@ -12,33 +12,9 @@ import { test, } from "~/utils/playwright"; import { createFormHelpers } from "~/utils/playwright-form"; -import { - editTeamPage, - TEAM_SEARCH_PAGE, - teamPage, - userPage, -} from "~/utils/urls"; - -test.describe("Team search page", () => { - test("filters teams", async ({ page }) => { - await seed(page); - await impersonate(page); - await navigate({ page, url: TEAM_SEARCH_PAGE }); - - const searchInput = page.getByTestId("team-search-input"); - const firstTeamName = page.getByTestId("team-0"); - const secondTeamName = page.getByTestId("team-1"); - - await expect(firstTeamName).toHaveText("Alliance Rogue"); - await expect(secondTeamName).toBeVisible(); - - await searchInput.fill("Alliance Rogue"); - await expect(secondTeamName).not.toBeVisible(); - - await firstTeamName.click(); - await expect(page).toHaveURL(/alliance-rogue/); - }); +import { editTeamPage, teamPage, userPage } from "~/utils/urls"; +test.describe("New team creation", () => { test("creates new team", async ({ page }) => { await seed(page); await impersonate(page, NZAP_TEST_ID); @@ -47,7 +23,7 @@ test.describe("Team search page", () => { await page.getByTestId("anything-adder-menu-button").click(); await page.getByTestId("menu-item-team").click(); - await expect(page).toHaveURL(/new=true/); + await expect(page).toHaveURL(/t\/new/); const form = createFormHelpers(page, createTeamSchema); await form.fill("name", "Chimera"); @@ -55,25 +31,6 @@ test.describe("Team search page", () => { await expect(page).toHaveURL(/chimera/); }); - - test("filters teams by tag & displays tag", async ({ page }) => { - await seed(page); - await impersonate(page, ADMIN_ID); - await navigate({ page, url: teamPage("alliance-rogue") }); - - await page.getByTestId("edit-team-button").click(); - await page.getByLabel("Tag").fill("AR"); - await submit(page, "edit-team-submit-button"); - - await navigate({ page, url: TEAM_SEARCH_PAGE }); - - const searchInput = page.getByTestId("team-search-input"); - await searchInput.fill("ar"); - - const firstTeamName = page.getByTestId("team-0"); - await expect(firstTeamName).toContainText("Alliance Rogue"); - await expect(firstTeamName).toContainText("AR"); - }); }); test.describe("Team page", () => { @@ -129,16 +86,13 @@ test.describe("Team page", () => { await seed(page); await impersonate(page, ADMIN_ID); - await navigate({ page, url: TEAM_SEARCH_PAGE }); - const firstTeamName = page.getByTestId("team-0"); - await firstTeamName.click(); + await navigate({ page, url: teamPage("alliance-rogue") }); await page.getByTestId("edit-team-button").click(); await page.getByTestId("delete-team-button").click(); await modalClickConfirmButton(page); - await expect(page).toHaveURL(TEAM_SEARCH_PAGE); - await expect(page.getByTestId("team-0")).not.toHaveText("Alliance Rogue"); + await expect(page).not.toHaveURL(/alliance-rogue/); }); test("resets invite code, joins team, leaves, rejoins", async ({ page }) => { diff --git a/e2e/tournament-streams.spec.ts b/e2e/tournament-streams.spec.ts index 1159922d9..7ef2e4b24 100644 --- a/e2e/tournament-streams.spec.ts +++ b/e2e/tournament-streams.spec.ts @@ -99,7 +99,8 @@ test.describe("Tournament streams", () => { await backToBracket(page); // The LIVE button should be visible since team 102 members are streaming - const liveButton = page.getByText("LIVE").first(); + const bracketsViewer = page.getByTestId("brackets-viewer"); + const liveButton = bracketsViewer.getByText("LIVE").first(); await expect(liveButton).toBeVisible(); // Click the LIVE button to open the popover diff --git a/e2e/user-page.spec.ts b/e2e/user-page.spec.ts index 8b515419a..616fff71d 100644 --- a/e2e/user-page.spec.ts +++ b/e2e/user-page.spec.ts @@ -16,8 +16,6 @@ import { userEditProfilePage, userPage } from "~/utils/urls"; const goToEditPage = (page: Page) => page.getByText("Edit", { exact: true }).click(); -const submitEditForm = (page: Page) => - page.getByText("Save", { exact: true }).click(); test.describe("User page", () => { test("uses badge pagination", async ({ page }) => { @@ -115,54 +113,38 @@ test.describe("User page", () => { await page.getByText("Stick 0 / Motion -5").isVisible(); }); - test("customizes user page colors and resets them", async ({ page }) => { + test("customizes theme colors and resets them", async ({ page }) => { await seed(page); await impersonate(page); - await navigate({ - page, - url: userPage({ discordId: ADMIN_DISCORD_ID, customUrl: "sendou" }), - }); - const body = page.locator("body"); - const bodyColor = () => - body.evaluate((element) => - window.getComputedStyle(element).getPropertyValue("--bg").trim(), + const htmlElement = page.locator("html"); + const hasCustomTheme = () => + htmlElement.evaluate( + (el) => el.style.getPropertyValue("--_base-h") !== "", ); - await expect(bodyColor()).resolves.toMatch(/#ebebf0/); + await navigate({ page, url: "/settings" }); - await goToEditPage(page); + // initially no custom theme + await expect(hasCustomTheme()).resolves.toBe(false); - await page.locator("span").filter({ hasText: "Custom colors" }).click(); + // change the base hue slider + const baseHueSlider = page.locator("#base-hue"); + await baseHueSlider.fill("120"); - await page.getByTestId("color-input-bg").fill("#4a412a"); - - // also test filling this because it's a special case as it also changes bg-lightest - await page.getByTestId("color-input-bg-lighter").fill("#4a412a"); - - await submitEditForm(page); - - // got redirected - await expect(page).not.toHaveURL(/edit/); + // save + await page.getByRole("button", { name: "Save" }).first().click(); await page.reload(); - await expect(bodyColor()).resolves.toMatch(/#4a412a/); - // then lets test resetting the colors is possible - await goToEditPage(page); - await page.locator("span").filter({ hasText: "Custom colors" }).click(); + // verify custom theme was applied + await expect(hasCustomTheme()).resolves.toBe(true); - for (const button of await page - .getByRole("button", { name: "Reset" }) - .all()) { - await button.click(); - } - - await submitEditForm(page); - - // got redirected - await expect(page).not.toHaveURL(/edit/); + // reset + await page.getByRole("button", { name: "Reset" }).first().click(); await page.reload(); - await expect(bodyColor()).resolves.toMatch(/#ebebf0/); + + // verify custom theme was removed + await expect(hasCustomTheme()).resolves.toBe(false); }); test("edits weapon pool", async ({ page }) => { diff --git a/locales/da/calendar.json b/locales/da/calendar.json index a7baefcb6..4ee77f0a3 100644 --- a/locales/da/calendar.json +++ b/locales/da/calendar.json @@ -79,5 +79,12 @@ "filter.applyAndDefault": "", "forms.draft": "", "forms.draftInfo": "", - "forms.draftBracketStartBlocked": "" + "forms.draftBracketStartBlocked": "", + "events.title": "", + "events.view.registered": "", + "events.view.hosting": "", + "events.view.scrims": "", + "events.empty": "", + "events.emptyAll": "", + "events.findOnCalendar": "" } diff --git a/locales/de/calendar.json b/locales/de/calendar.json index 00f8f418c..5cee7f59f 100644 --- a/locales/de/calendar.json +++ b/locales/de/calendar.json @@ -79,5 +79,12 @@ "filter.applyAndDefault": "", "forms.draft": "", "forms.draftInfo": "", - "forms.draftBracketStartBlocked": "" + "forms.draftBracketStartBlocked": "", + "events.title": "", + "events.view.registered": "", + "events.view.hosting": "", + "events.view.scrims": "", + "events.empty": "", + "events.emptyAll": "", + "events.findOnCalendar": "" } diff --git a/locales/en/calendar.json b/locales/en/calendar.json index d6a15d3dd..79add1679 100644 --- a/locales/en/calendar.json +++ b/locales/en/calendar.json @@ -79,5 +79,12 @@ "filter.applyAndDefault": "Apply & make default", "forms.draft": "Draft", "forms.draftInfo": "Draft tournaments are hidden and only visible to organizers. The tournament must be opened (by disabling this toggle) before any bracket can be started.", - "forms.draftBracketStartBlocked": "Tournament is in draft mode. Edit the tournament and disable the draft toggle before starting the bracket." + "forms.draftBracketStartBlocked": "Tournament is in draft mode. Edit the tournament and disable the draft toggle before starting the bracket.", + "events.title": "My Events", + "events.view.registered": "Registered", + "events.view.hosting": "Hosting", + "events.view.scrims": "Scrims", + "events.empty": "No events in this category", + "events.emptyAll": "You have no upcoming events.", + "events.findOnCalendar": "Find an event to join on the calendar!" } diff --git a/locales/es-ES/calendar.json b/locales/es-ES/calendar.json index b005cae62..5d090bcac 100644 --- a/locales/es-ES/calendar.json +++ b/locales/es-ES/calendar.json @@ -81,5 +81,12 @@ "filter.applyAndDefault": "", "forms.draft": "", "forms.draftInfo": "", - "forms.draftBracketStartBlocked": "" + "forms.draftBracketStartBlocked": "", + "events.title": "", + "events.view.registered": "", + "events.view.hosting": "", + "events.view.scrims": "", + "events.empty": "", + "events.emptyAll": "", + "events.findOnCalendar": "" } diff --git a/locales/es-US/calendar.json b/locales/es-US/calendar.json index b005cae62..5d090bcac 100644 --- a/locales/es-US/calendar.json +++ b/locales/es-US/calendar.json @@ -81,5 +81,12 @@ "filter.applyAndDefault": "", "forms.draft": "", "forms.draftInfo": "", - "forms.draftBracketStartBlocked": "" + "forms.draftBracketStartBlocked": "", + "events.title": "", + "events.view.registered": "", + "events.view.hosting": "", + "events.view.scrims": "", + "events.empty": "", + "events.emptyAll": "", + "events.findOnCalendar": "" } diff --git a/locales/fr-CA/calendar.json b/locales/fr-CA/calendar.json index 4f84120c7..dc078ffb7 100644 --- a/locales/fr-CA/calendar.json +++ b/locales/fr-CA/calendar.json @@ -81,5 +81,12 @@ "filter.applyAndDefault": "", "forms.draft": "", "forms.draftInfo": "", - "forms.draftBracketStartBlocked": "" + "forms.draftBracketStartBlocked": "", + "events.title": "", + "events.view.registered": "", + "events.view.hosting": "", + "events.view.scrims": "", + "events.empty": "", + "events.emptyAll": "", + "events.findOnCalendar": "" } diff --git a/locales/fr-EU/calendar.json b/locales/fr-EU/calendar.json index 4f84120c7..dc078ffb7 100644 --- a/locales/fr-EU/calendar.json +++ b/locales/fr-EU/calendar.json @@ -81,5 +81,12 @@ "filter.applyAndDefault": "", "forms.draft": "", "forms.draftInfo": "", - "forms.draftBracketStartBlocked": "" + "forms.draftBracketStartBlocked": "", + "events.title": "", + "events.view.registered": "", + "events.view.hosting": "", + "events.view.scrims": "", + "events.empty": "", + "events.emptyAll": "", + "events.findOnCalendar": "" } diff --git a/locales/he/calendar.json b/locales/he/calendar.json index 2a16dd62e..f99a4eed0 100644 --- a/locales/he/calendar.json +++ b/locales/he/calendar.json @@ -81,5 +81,12 @@ "filter.applyAndDefault": "החל והפוך לברירת מחדל", "forms.draft": "", "forms.draftInfo": "", - "forms.draftBracketStartBlocked": "" + "forms.draftBracketStartBlocked": "", + "events.title": "", + "events.view.registered": "", + "events.view.hosting": "", + "events.view.scrims": "", + "events.empty": "", + "events.emptyAll": "", + "events.findOnCalendar": "" } diff --git a/locales/it/calendar.json b/locales/it/calendar.json index 3dbf60a04..f6b586379 100644 --- a/locales/it/calendar.json +++ b/locales/it/calendar.json @@ -81,5 +81,12 @@ "filter.applyAndDefault": "", "forms.draft": "", "forms.draftInfo": "", - "forms.draftBracketStartBlocked": "" + "forms.draftBracketStartBlocked": "", + "events.title": "", + "events.view.registered": "", + "events.view.hosting": "", + "events.view.scrims": "", + "events.empty": "", + "events.emptyAll": "", + "events.findOnCalendar": "" } diff --git a/locales/ja/calendar.json b/locales/ja/calendar.json index a654dd3cf..ee4f47556 100644 --- a/locales/ja/calendar.json +++ b/locales/ja/calendar.json @@ -75,5 +75,12 @@ "filter.applyAndDefault": "", "forms.draft": "", "forms.draftInfo": "", - "forms.draftBracketStartBlocked": "" + "forms.draftBracketStartBlocked": "", + "events.title": "", + "events.view.registered": "", + "events.view.hosting": "", + "events.view.scrims": "", + "events.empty": "", + "events.emptyAll": "", + "events.findOnCalendar": "" } diff --git a/locales/ko/calendar.json b/locales/ko/calendar.json index f6c4d3aea..4949c5605 100644 --- a/locales/ko/calendar.json +++ b/locales/ko/calendar.json @@ -75,5 +75,12 @@ "filter.applyAndDefault": "", "forms.draft": "", "forms.draftInfo": "", - "forms.draftBracketStartBlocked": "" + "forms.draftBracketStartBlocked": "", + "events.title": "", + "events.view.registered": "", + "events.view.hosting": "", + "events.view.scrims": "", + "events.empty": "", + "events.emptyAll": "", + "events.findOnCalendar": "" } diff --git a/locales/nl/calendar.json b/locales/nl/calendar.json index 4d196d1c6..d93969574 100644 --- a/locales/nl/calendar.json +++ b/locales/nl/calendar.json @@ -79,5 +79,12 @@ "filter.applyAndDefault": "", "forms.draft": "", "forms.draftInfo": "", - "forms.draftBracketStartBlocked": "" + "forms.draftBracketStartBlocked": "", + "events.title": "", + "events.view.registered": "", + "events.view.hosting": "", + "events.view.scrims": "", + "events.empty": "", + "events.emptyAll": "", + "events.findOnCalendar": "" } diff --git a/locales/pl/calendar.json b/locales/pl/calendar.json index 40c933639..3783cab0c 100644 --- a/locales/pl/calendar.json +++ b/locales/pl/calendar.json @@ -83,5 +83,12 @@ "filter.applyAndDefault": "", "forms.draft": "", "forms.draftInfo": "", - "forms.draftBracketStartBlocked": "" + "forms.draftBracketStartBlocked": "", + "events.title": "", + "events.view.registered": "", + "events.view.hosting": "", + "events.view.scrims": "", + "events.empty": "", + "events.emptyAll": "", + "events.findOnCalendar": "" } diff --git a/locales/pt-BR/calendar.json b/locales/pt-BR/calendar.json index cfefc88a9..39d841705 100644 --- a/locales/pt-BR/calendar.json +++ b/locales/pt-BR/calendar.json @@ -81,5 +81,12 @@ "filter.applyAndDefault": "", "forms.draft": "", "forms.draftInfo": "", - "forms.draftBracketStartBlocked": "" + "forms.draftBracketStartBlocked": "", + "events.title": "", + "events.view.registered": "", + "events.view.hosting": "", + "events.view.scrims": "", + "events.empty": "", + "events.emptyAll": "", + "events.findOnCalendar": "" } diff --git a/locales/ru/calendar.json b/locales/ru/calendar.json index b882eae0f..be936a053 100644 --- a/locales/ru/calendar.json +++ b/locales/ru/calendar.json @@ -83,5 +83,12 @@ "filter.applyAndDefault": "", "forms.draft": "", "forms.draftInfo": "", - "forms.draftBracketStartBlocked": "" + "forms.draftBracketStartBlocked": "", + "events.title": "", + "events.view.registered": "", + "events.view.hosting": "", + "events.view.scrims": "", + "events.empty": "", + "events.emptyAll": "", + "events.findOnCalendar": "" } diff --git a/locales/zh/calendar.json b/locales/zh/calendar.json index 639d367cf..1b8170d23 100644 --- a/locales/zh/calendar.json +++ b/locales/zh/calendar.json @@ -75,5 +75,12 @@ "filter.applyAndDefault": "", "forms.draft": "", "forms.draftInfo": "", - "forms.draftBracketStartBlocked": "" + "forms.draftBracketStartBlocked": "", + "events.title": "", + "events.view.registered": "", + "events.view.hosting": "", + "events.view.scrims": "", + "events.empty": "", + "events.emptyAll": "", + "events.findOnCalendar": "" } diff --git a/vite.config.ts b/vite.config.ts index 56f9eb84e..b792785a9 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -19,6 +19,20 @@ export default defineConfig(({ mode }) => { }, }, plugins: [ + { + // Wraps CSS modules in @layer components so utility classes always win. + // The layer order declaration is prepended to each module because in Vite + // dev mode, module