diff --git a/docker/frontend/Dockerfile b/docker/frontend/Dockerfile index b918fc8cd..0c845be18 100644 --- a/docker/frontend/Dockerfile +++ b/docker/frontend/Dockerfile @@ -11,6 +11,14 @@ WORKDIR /app COPY frontend/package.json frontend/package-lock.json ./ COPY frontend/scripts ./scripts +# Font download configuration for internal deployments +ARG GOOGLE_SANS_CSS_URLS="" +ARG SKIP_UI_FONT_DOWNLOAD="" +ARG SKIP_PDF_FONT_DOWNLOAD="" +ENV GOOGLE_SANS_CSS_URLS=${GOOGLE_SANS_CSS_URLS} +ENV SKIP_UI_FONT_DOWNLOAD=${SKIP_UI_FONT_DOWNLOAD} +ENV SKIP_PDF_FONT_DOWNLOAD=${SKIP_PDF_FONT_DOWNLOAD} + # Install dependencies (this layer will be cached, only reinstall when package.json changes) RUN npm ci && npm cache clean --force diff --git a/docker/standalone/Dockerfile b/docker/standalone/Dockerfile index ea63b69d8..fb52b39ef 100644 --- a/docker/standalone/Dockerfile +++ b/docker/standalone/Dockerfile @@ -14,6 +14,14 @@ WORKDIR /app COPY frontend/package.json frontend/package-lock.json ./ COPY frontend/scripts ./scripts +# Font download configuration for internal deployments +ARG GOOGLE_SANS_CSS_URLS="" +ARG SKIP_UI_FONT_DOWNLOAD="" +ARG SKIP_PDF_FONT_DOWNLOAD="" +ENV GOOGLE_SANS_CSS_URLS=${GOOGLE_SANS_CSS_URLS} +ENV SKIP_UI_FONT_DOWNLOAD=${SKIP_UI_FONT_DOWNLOAD} +ENV SKIP_PDF_FONT_DOWNLOAD=${SKIP_PDF_FONT_DOWNLOAD} + # Install dependencies RUN npm ci && npm cache clean --force diff --git a/frontend/.gitignore b/frontend/.gitignore index 5a67d6e1d..c64f1b45a 100644 --- a/frontend/.gitignore +++ b/frontend/.gitignore @@ -20,3 +20,5 @@ public/fonts/*.ttf public/fonts/*.otf public/fonts/*.woff public/fonts/*.woff2 +# Google Sans woff2 files (downloaded at build time, not checked in) +public/fonts/google-sans/ diff --git a/frontend/scripts/download-fonts.cjs b/frontend/scripts/download-fonts.cjs index 296364aa1..cd7af04f4 100644 --- a/frontend/scripts/download-fonts.cjs +++ b/frontend/scripts/download-fonts.cjs @@ -4,11 +4,16 @@ // SPDX-License-Identifier: Apache-2.0 /** - * Download fonts script for PDF generation - * - Supports mirror fallback - * - Supports skip via env - * - Shows progress & timeout + * Download fonts for: + * 1) PDF rendering (CJK) + * 2) Local web typography (Google Sans Flex / Google Sans) + * + * Features: + * - Mirror fallback + * - Skip via environment variables + * - Progress and timeout * - Atomic write with temp file + * - Configurable Google Sans CSS source URL(s) for internal deployments */ const https = require('https') @@ -16,18 +21,24 @@ const http = require('http') const fs = require('fs') const path = require('path') -/* ========================= - * Environment switches - * ========================= */ +/* Environment switches */ if (process.env.SKIP_FONT_DOWNLOAD === '1') { console.log('🚫 Skip font download (SKIP_FONT_DOWNLOAD=1)') process.exit(0) } -/* ========================= - * Font configuration - * ========================= */ -const FONTS = [ +/* Paths */ +const FONTS_DIR = path.join(__dirname, '..', 'public', 'fonts') +const PDF_FONT_DIR = FONTS_DIR +const GOOGLE_SANS_DIR = path.join(FONTS_DIR, 'google-sans') +const GOOGLE_SANS_CSS_OUTPUT = path.join(__dirname, '..', 'src', 'app', 'google-sans-local.css') +const DOWNLOAD_TIMEOUT = 30_000 // 30s +const GOOGLE_FONTS_USER_AGENT = + process.env.GOOGLE_FONT_USER_AGENT || + 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0 Safari/537.36' + +/* PDF font configuration */ +const PDF_FONTS = [ { name: 'SourceHanSansSC-VF.ttf', description: 'Source Han Sans SC Variable (CJK support for PDF)', @@ -41,12 +52,20 @@ const FONTS = [ }, ] -const FONTS_DIR = path.join(__dirname, '..', 'public', 'fonts') -const DOWNLOAD_TIMEOUT = 30_000 // 30s +/* Google Sans configuration */ +const defaultGoogleSansCssUrls = [ + 'https://fonts.googleapis.com/css2?family=Google+Sans:wght@400;500;700&family=Google+Sans+Flex:wght@400;500;700&display=swap', +] + +const configuredGoogleSansCssUrls = (process.env.GOOGLE_SANS_CSS_URLS || '') + .split(',') + .map(url => url.trim()) + .filter(Boolean) + +const googleSansCssUrls = configuredGoogleSansCssUrls.length + ? configuredGoogleSansCssUrls + : defaultGoogleSansCssUrls -/* ========================= - * Utilities - * ========================= */ function formatSize(bytes) { if (bytes < 1024) return `${bytes} B` if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB` @@ -59,12 +78,20 @@ function isFontComplete(filePath, minSize) { return !minSize || size >= minSize } -/* ========================= - * Core download logic - * ========================= */ -function downloadFile(url, destPath, maxRedirects = 5) { +function ensureDirectory(dirPath) { + if (!fs.existsSync(dirPath)) { + fs.mkdirSync(dirPath, { recursive: true }) + } +} + +function resolveRedirectUrl(currentUrl, location) { + return new URL(location, currentUrl).toString() +} + +function downloadFile(url, destPath, options = {}, maxRedirects = 5) { const tempPath = destPath + '.downloading' const protocol = url.startsWith('https') ? https : http + const headers = options.headers || {} return new Promise((resolve, reject) => { if (maxRedirects <= 0) { @@ -72,11 +99,12 @@ function downloadFile(url, destPath, maxRedirects = 5) { return } - const req = protocol.get(url, res => { + const req = protocol.get(url, { headers }, res => { // Redirect support if (res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) { - console.log(` β†ͺ Redirect: ${res.headers.location}`) - return downloadFile(res.headers.location, destPath, maxRedirects - 1) + const redirectUrl = resolveRedirectUrl(url, res.headers.location) + console.log(` β†ͺ Redirect: ${redirectUrl}`) + return downloadFile(redirectUrl, destPath, options, maxRedirects - 1) .then(resolve) .catch(reject) } @@ -135,13 +163,53 @@ function downloadFile(url, destPath, maxRedirects = 5) { }) } -async function downloadWithFallback(urls, destPath) { +function downloadText(url, options = {}, maxRedirects = 5) { + const protocol = url.startsWith('https') ? https : http + const headers = options.headers || {} + + return new Promise((resolve, reject) => { + if (maxRedirects <= 0) { + reject(new Error('Too many redirects')) + return + } + + const req = protocol.get(url, { headers }, res => { + if (res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) { + const redirectUrl = resolveRedirectUrl(url, res.headers.location) + return downloadText(redirectUrl, options, maxRedirects - 1).then(resolve).catch(reject) + } + + if (res.statusCode !== 200) { + reject(new Error(`HTTP ${res.statusCode}`)) + return + } + + let data = '' + res.setEncoding('utf8') + res.on('data', chunk => { + data += chunk + }) + res.on('end', () => resolve(data)) + }) + + req.setTimeout(DOWNLOAD_TIMEOUT, () => { + req.destroy(new Error('Download timeout')) + }) + + req.on('error', reject) + }) +} + +async function downloadWithFallback(urls, downloader, validator) { let lastError for (const url of urls) { try { console.log(` 🌐 Try: ${url}`) - await downloadFile(url, destPath) - return + const result = await downloader(url) + if (validator) { + await validator(result, url) + } + return { url, result } } catch (err) { console.warn(` ⚠ Failed: ${err.message}`) lastError = err @@ -150,21 +218,35 @@ async function downloadWithFallback(urls, destPath) { throw lastError } -/* ========================= - * Main - * ========================= */ -async function main() { - console.log('πŸ“¦ Downloading fonts for PDF generation...\n') +function normalizeFontUrl(rawUrl) { + return rawUrl.trim().replace(/^['"]|['"]$/g, '') +} - if (!fs.existsSync(FONTS_DIR)) { - fs.mkdirSync(FONTS_DIR, { recursive: true }) - console.log(`Created directory: ${FONTS_DIR}\n`) +function collectFontUrlsFromCss(cssText) { + const regex = /url\(([^)]+)\)/g + const urls = [] + for (const match of cssText.matchAll(regex)) { + const url = normalizeFontUrl(match[1]) + if (url.startsWith('http://') || url.startsWith('https://')) { + urls.push(url) + } } + return Array.from(new Set(urls)) +} + +function toLocalFileName(fontUrl, index) { + const urlObj = new URL(fontUrl) + const baseName = path.basename(urlObj.pathname) + const safeBaseName = baseName.replace(/[^A-Za-z0-9._-]/g, '_') + const ext = path.extname(safeBaseName) || '.woff2' + return `${String(index).padStart(2, '0')}-${safeBaseName || `font${ext}`}` +} +async function downloadPdfFonts() { let hasErrors = false - for (const font of FONTS) { - const destPath = path.join(FONTS_DIR, font.name) + for (const font of PDF_FONTS) { + const destPath = path.join(PDF_FONT_DIR, font.name) const tempPath = destPath + '.downloading' if (fs.existsSync(tempPath)) { @@ -185,13 +267,18 @@ async function main() { console.log(` ${font.description}`) try { - await downloadWithFallback(font.urls, destPath) + await downloadWithFallback( + font.urls, + url => downloadFile(url, destPath), + () => { + const { size } = fs.statSync(destPath) + if (font.minSize && size < font.minSize) { + throw new Error(`File too small (${formatSize(size)})`) + } + } + ) const { size } = fs.statSync(destPath) - if (font.minSize && size < font.minSize) { - throw new Error(`File too small (${formatSize(size)})`) - } - console.log(`βœ“ Downloaded ${font.name} (${formatSize(size)})\n`) } catch (err) { if (fs.existsSync(destPath)) fs.unlinkSync(destPath) @@ -201,10 +288,85 @@ async function main() { } } + return !hasErrors +} + +async function downloadGoogleSansAssets() { + try { + console.log('⬇ Downloading local Google Sans assets') + console.log(` CSS source candidates: ${googleSansCssUrls.join(', ')}`) + + const { result: cssText } = await downloadWithFallback(googleSansCssUrls, url => + downloadText(url, { + headers: { + 'User-Agent': GOOGLE_FONTS_USER_AGENT, + }, + }) + ) + + const remoteFontUrls = collectFontUrlsFromCss(cssText) + if (remoteFontUrls.length === 0) { + throw new Error('No font URLs found in Google Sans CSS response') + } + + ensureDirectory(GOOGLE_SANS_DIR) + const fileMap = new Map() + + for (let i = 0; i < remoteFontUrls.length; i++) { + const remoteUrl = remoteFontUrls[i] + const fileName = toLocalFileName(remoteUrl, i + 1) + const destPath = path.join(GOOGLE_SANS_DIR, fileName) + fileMap.set(remoteUrl, fileName) + + await downloadFile(remoteUrl, destPath, { + headers: { + 'User-Agent': GOOGLE_FONTS_USER_AGENT, + }, + }) + } + + const localCss = cssText.replace(/url\(([^)]+)\)/g, (match, rawUrl) => { + const normalized = normalizeFontUrl(rawUrl) + const localName = fileMap.get(normalized) + if (!localName) return match + return `url('/fonts/google-sans/${localName}')` + }) + + fs.writeFileSync(GOOGLE_SANS_CSS_OUTPUT, localCss, 'utf8') + console.log(`βœ“ Generated ${path.relative(process.cwd(), GOOGLE_SANS_CSS_OUTPUT)}\n`) + return true + } catch (err) { + console.error(`βœ— Failed to download local Google Sans assets: ${err.message}`) + console.error(' Web UI will fall back to system fonts.\n') + return false + } +} + +async function main() { + console.log('πŸ“¦ Downloading font assets...\n') + + ensureDirectory(FONTS_DIR) + + let hasErrors = false + + if (process.env.SKIP_PDF_FONT_DOWNLOAD !== '1') { + const pdfSuccess = await downloadPdfFonts() + if (!pdfSuccess) hasErrors = true + } else { + console.log('🚫 Skip PDF font download (SKIP_PDF_FONT_DOWNLOAD=1)\n') + } + + if (process.env.SKIP_UI_FONT_DOWNLOAD !== '1') { + const uiSuccess = await downloadGoogleSansAssets() + if (!uiSuccess) hasErrors = true + } else { + console.log('🚫 Skip UI font download (SKIP_UI_FONT_DOWNLOAD=1)\n') + } + if (hasErrors) { - console.log('⚠ Some fonts failed to download. Build continues.') + console.log('⚠ Some font assets failed to download. Build continues.') } else { - console.log('βœ… All fonts downloaded successfully!') + console.log('βœ… All font assets downloaded successfully!') } } diff --git a/frontend/src/apis/skillMarket.ts b/frontend/src/apis/skillMarket.ts index 874616b61..26eb614ce 100644 --- a/frontend/src/apis/skillMarket.ts +++ b/frontend/src/apis/skillMarket.ts @@ -159,7 +159,10 @@ export async function searchSkills(params: SearchSkillsParams): Promise { // FastAPI wraps errors in a detail object, check for it first const detail = errorData.detail const errorMessage = - detail?.error || detail?.message || errorData.error || errorData.message || + detail?.error || + detail?.message || + errorData.error || + errorData.message || `HTTP ${response.status}: Failed to download skill` throw new Error(errorMessage) } diff --git a/frontend/src/app/globals.css b/frontend/src/app/globals.css index 773d31fa5..9f7a19246 100644 --- a/frontend/src/app/globals.css +++ b/frontend/src/app/globals.css @@ -4,6 +4,8 @@ * SPDX-License-Identifier: Apache-2.0 */ +@import './google-sans-local.css'; + @tailwind base; @tailwind components; @tailwind utilities; @@ -79,14 +81,17 @@ body { background-attachment: fixed; overflow-x: hidden; font-family: - 'PingFang SC', + 'Google Sans Flex', + 'Google Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, - 'Noto Sans', + 'PingFang SC', + 'Hiragino Sans GB', + 'Microsoft YaHei', sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', diff --git a/frontend/src/app/google-sans-local.css b/frontend/src/app/google-sans-local.css new file mode 100644 index 000000000..a8c81578f --- /dev/null +++ b/frontend/src/app/google-sans-local.css @@ -0,0 +1,1308 @@ +/* armenian */ +@font-face { + font-family: 'Google Sans'; + font-style: normal; + font-weight: 400; + font-display: swap; + src: url('/fonts/google-sans/01-4UasrENHsxJlGDuGo1OIlJfC6l_24rlCK1Yo_Iqcsih3SAyH6cAwhX9RPiIUvaYr.woff2') + format('woff2'); + unicode-range: U+0308, U+0530-058F, U+2010, U+2024, U+25CC, U+FB13-FB17; +} +/* bengali */ +@font-face { + font-family: 'Google Sans'; + font-style: normal; + font-weight: 400; + font-display: swap; + src: url('/fonts/google-sans/02-4UasrENHsxJlGDuGo1OIlJfC6l_24rlCK1Yo_Iqcsih3SAyH6cAwhX9RPiAUvaYr.woff2') + format('woff2'); + unicode-range: + U+0951-0952, U+0964-0965, U+0980-09FE, U+1CD0, U+1CD2, U+1CD5-1CD6, U+1CD8, U+1CE1, U+1CEA, + U+1CED, U+1CF2, U+1CF5-1CF7, U+200C-200D, U+20B9, U+25CC, U+A8F1; +} +/* canadian-aboriginal */ +@font-face { + font-family: 'Google Sans'; + font-style: normal; + font-weight: 400; + font-display: swap; + src: url('/fonts/google-sans/03-4UasrENHsxJlGDuGo1OIlJfC6l_24rlCK1Yo_Iqcsih3SAyH6cAwhX9RPh0UvaYr.woff2') + format('woff2'); + unicode-range: + U+02C7, U+02D8-02D9, U+02DB, U+0307, U+1400-167F, U+18B0-18F5, U+25CC, U+11AB0-11ABF; +} +/* cyrillic-ext */ +@font-face { + font-family: 'Google Sans'; + font-style: normal; + font-weight: 400; + font-display: swap; + src: url('/fonts/google-sans/04-4UasrENHsxJlGDuGo1OIlJfC6l_24rlCK1Yo_Iqcsih3SAyH6cAwhX9RPj8UvaYr.woff2') + format('woff2'); + unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; +} +/* cyrillic */ +@font-face { + font-family: 'Google Sans'; + font-style: normal; + font-weight: 400; + font-display: swap; + src: url('/fonts/google-sans/05-4UasrENHsxJlGDuGo1OIlJfC6l_24rlCK1Yo_Iqcsih3SAyH6cAwhX9RPjYUvaYr.woff2') + format('woff2'); + unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; +} +/* devanagari */ +@font-face { + font-family: 'Google Sans'; + font-style: normal; + font-weight: 400; + font-display: swap; + src: url('/fonts/google-sans/06-4UasrENHsxJlGDuGo1OIlJfC6l_24rlCK1Yo_Iqcsih3SAyH6cAwhX9RPjMUvaYr.woff2') + format('woff2'); + unicode-range: + U+0900-097F, U+1CD0-1CF9, U+200C-200D, U+20A8, U+20B9, U+20F0, U+25CC, U+A830-A839, U+A8E0-A8FF, + U+11B00-11B09; +} +/* ethiopic */ +@font-face { + font-family: 'Google Sans'; + font-style: normal; + font-weight: 400; + font-display: swap; + src: url('/fonts/google-sans/07-4UasrENHsxJlGDuGo1OIlJfC6l_24rlCK1Yo_Iqcsih3SAyH6cAwhX9RPiMUvaYr.woff2') + format('woff2'); + unicode-range: + U+030E, U+1200-1399, U+2D80-2DDE, U+AB01-AB2E, U+1E7E0-1E7E6, U+1E7E8-1E7EB, U+1E7ED-1E7EE, + U+1E7F0-1E7FE; +} +/* georgian */ +@font-face { + font-family: 'Google Sans'; + font-style: normal; + font-weight: 400; + font-display: swap; + src: url('/fonts/google-sans/08-4UasrENHsxJlGDuGo1OIlJfC6l_24rlCK1Yo_Iqcsih3SAyH6cAwhX9RPi0UvaYr.woff2') + format('woff2'); + unicode-range: U+0589, U+10A0-10FF, U+1C90-1CBA, U+1CBD-1CBF, U+205A, U+2D00-2D2F, U+2E31; +} +/* greek-ext */ +@font-face { + font-family: 'Google Sans'; + font-style: normal; + font-weight: 400; + font-display: swap; + src: url('/fonts/google-sans/09-4UasrENHsxJlGDuGo1OIlJfC6l_24rlCK1Yo_Iqcsih3SAyH6cAwhX9RPj4UvaYr.woff2') + format('woff2'); + unicode-range: U+1F00-1FFF; +} +/* greek */ +@font-face { + font-family: 'Google Sans'; + font-style: normal; + font-weight: 400; + font-display: swap; + src: url('/fonts/google-sans/10-4UasrENHsxJlGDuGo1OIlJfC6l_24rlCK1Yo_Iqcsih3SAyH6cAwhX9RPjEUvaYr.woff2') + format('woff2'); + unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF; +} +/* gujarati */ +@font-face { + font-family: 'Google Sans'; + font-style: normal; + font-weight: 400; + font-display: swap; + src: url('/fonts/google-sans/11-4UasrENHsxJlGDuGo1OIlJfC6l_24rlCK1Yo_Iqcsih3SAyH6cAwhX9RPikUvaYr.woff2') + format('woff2'); + unicode-range: U+0951-0952, U+0964-0965, U+0A80-0AFF, U+200C-200D, U+20B9, U+25CC, U+A830-A839; +} +/* gurmukhi */ +@font-face { + font-family: 'Google Sans'; + font-style: normal; + font-weight: 400; + font-display: swap; + src: url('/fonts/google-sans/12-4UasrENHsxJlGDuGo1OIlJfC6l_24rlCK1Yo_Iqcsih3SAyH6cAwhX9RPhEUvaYr.woff2') + format('woff2'); + unicode-range: + U+0951-0952, U+0964-0965, U+0A01-0A76, U+200C-200D, U+20B9, U+25CC, U+262C, U+A830-A839; +} +/* hebrew */ +@font-face { + font-family: 'Google Sans'; + font-style: normal; + font-weight: 400; + font-display: swap; + src: url('/fonts/google-sans/13-4UasrENHsxJlGDuGo1OIlJfC6l_24rlCK1Yo_Iqcsih3SAyH6cAwhX9RPjAUvaYr.woff2') + format('woff2'); + unicode-range: U+0307-0308, U+0590-05FF, U+200C-2010, U+20AA, U+25CC, U+FB1D-FB4F; +} +/* khmer */ +@font-face { + font-family: 'Google Sans'; + font-style: normal; + font-weight: 400; + font-display: swap; + src: url('/fonts/google-sans/14-4UasrENHsxJlGDuGo1OIlJfC6l_24rlCK1Yo_Iqcsih3SAyH6cAwhX9RPjkUvaYr.woff2') + format('woff2'); + unicode-range: U+1780-17FF, U+19E0-19FF, U+200C-200D, U+25CC; +} +/* lao */ +@font-face { + font-family: 'Google Sans'; + font-style: normal; + font-weight: 400; + font-display: swap; + src: url('/fonts/google-sans/15-4UasrENHsxJlGDuGo1OIlJfC6l_24rlCK1Yo_Iqcsih3SAyH6cAwhX9RPjsUvaYr.woff2') + format('woff2'); + unicode-range: U+0E81-0EDF, U+200C-200D, U+25CC; +} +/* malayalam */ +@font-face { + font-family: 'Google Sans'; + font-style: normal; + font-weight: 400; + font-display: swap; + src: url('/fonts/google-sans/16-4UasrENHsxJlGDuGo1OIlJfC6l_24rlCK1Yo_Iqcsih3SAyH6cAwhX9RPioUvaYr.woff2') + format('woff2'); + unicode-range: + U+0307, U+0323, U+0951-0952, U+0964-0965, U+0D00-0D7F, U+1CDA, U+1CF2, U+200C-200D, U+20B9, + U+25CC, U+A830-A832; +} +/* oriya */ +@font-face { + font-family: 'Google Sans'; + font-style: normal; + font-weight: 400; + font-display: swap; + src: url('/fonts/google-sans/17-4UasrENHsxJlGDuGo1OIlJfC6l_24rlCK1Yo_Iqcsih3SAyH6cAwhX9RPisUvaYr.woff2') + format('woff2'); + unicode-range: U+0951-0952, U+0964-0965, U+0B01-0B77, U+1CDA, U+1CF2, U+200C-200D, U+20B9, U+25CC; +} +/* sinhala */ +@font-face { + font-family: 'Google Sans'; + font-style: normal; + font-weight: 400; + font-display: swap; + src: url('/fonts/google-sans/18-4UasrENHsxJlGDuGo1OIlJfC6l_24rlCK1Yo_Iqcsih3SAyH6cAwhX9RPi8UvaYr.woff2') + format('woff2'); + unicode-range: U+0964-0965, U+0D81-0DF4, U+1CF2, U+200C-200D, U+25CC, U+111E1-111F4; +} +/* symbols */ +@font-face { + font-family: 'Google Sans'; + font-style: normal; + font-weight: 400; + font-display: swap; + src: url('/fonts/google-sans/19-4UasrENHsxJlGDuGo1OIlJfC6l_24rlCK1Yo_Iqcsih3SAyH6cAwhX9RPlwUvaYr.woff2') + format('woff2'); + unicode-range: + U+0001-000C, U+000E-001F, U+007F-009F, U+20DD-20E0, U+20E2-20E4, U+2150-218F, U+2190, U+2192, + U+2194-2199, U+21AF, U+21E6-21F0, U+21F3, U+2218-2219, U+2299, U+22C4-22C6, U+2300-243F, + U+2440-244A, U+2460-24FF, U+25A0-27BF, U+2800-28FF, U+2921-2922, U+2981, U+29BF, U+29EB, + U+2B00-2BFF, U+4DC0-4DFF, U+FFF9-FFFB, U+10140-1018E, U+10190-1019C, U+101A0, U+101D0-101FD, + U+102E0-102FB, U+10E60-10E7E, U+1D2C0-1D2D3, U+1D2E0-1D37F, U+1F000-1F0FF, U+1F100-1F1AD, + U+1F1E6-1F1FF, U+1F30D-1F30F, U+1F315, U+1F31C, U+1F31E, U+1F320-1F32C, U+1F336, U+1F378, + U+1F37D, U+1F382, U+1F393-1F39F, U+1F3A7-1F3A8, U+1F3AC-1F3AF, U+1F3C2, U+1F3C4-1F3C6, + U+1F3CA-1F3CE, U+1F3D4-1F3E0, U+1F3ED, U+1F3F1-1F3F3, U+1F3F5-1F3F7, U+1F408, U+1F415, U+1F41F, + U+1F426, U+1F43F, U+1F441-1F442, U+1F444, U+1F446-1F449, U+1F44C-1F44E, U+1F453, U+1F46A, + U+1F47D, U+1F4A3, U+1F4B0, U+1F4B3, U+1F4B9, U+1F4BB, U+1F4BF, U+1F4C8-1F4CB, U+1F4D6, U+1F4DA, + U+1F4DF, U+1F4E3-1F4E6, U+1F4EA-1F4ED, U+1F4F7, U+1F4F9-1F4FB, U+1F4FD-1F4FE, U+1F503, + U+1F507-1F50B, U+1F50D, U+1F512-1F513, U+1F53E-1F54A, U+1F54F-1F5FA, U+1F610, U+1F650-1F67F, + U+1F687, U+1F68D, U+1F691, U+1F694, U+1F698, U+1F6AD, U+1F6B2, U+1F6B9-1F6BA, U+1F6BC, + U+1F6C6-1F6CF, U+1F6D3-1F6D7, U+1F6E0-1F6EA, U+1F6F0-1F6F3, U+1F6F7-1F6FC, U+1F700-1F7FF, + U+1F800-1F80B, U+1F810-1F847, U+1F850-1F859, U+1F860-1F887, U+1F890-1F8AD, U+1F8B0-1F8BB, + U+1F8C0-1F8C1, U+1F900-1F90B, U+1F93B, U+1F946, U+1F984, U+1F996, U+1F9E9, U+1FA00-1FA6F, + U+1FA70-1FA7C, U+1FA80-1FA89, U+1FA8F-1FAC6, U+1FACE-1FADC, U+1FADF-1FAE9, U+1FAF0-1FAF8, + U+1FB00-1FBFF; +} +/* tamil */ +@font-face { + font-family: 'Google Sans'; + font-style: normal; + font-weight: 400; + font-display: swap; + src: url('/fonts/google-sans/20-4UasrENHsxJlGDuGo1OIlJfC6l_24rlCK1Yo_Iqcsih3SAyH6cAwhX9RPiQUvaYr.woff2') + format('woff2'); + unicode-range: U+0964-0965, U+0B82-0BFA, U+200C-200D, U+20B9, U+25CC; +} +/* telugu */ +@font-face { + font-family: 'Google Sans'; + font-style: normal; + font-weight: 400; + font-display: swap; + src: url('/fonts/google-sans/21-4UasrENHsxJlGDuGo1OIlJfC6l_24rlCK1Yo_Iqcsih3SAyH6cAwhX9RPi4UvaYr.woff2') + format('woff2'); + unicode-range: U+0951-0952, U+0964-0965, U+0C00-0C7F, U+1CDA, U+1CF2, U+200C-200D, U+25CC; +} +/* thai */ +@font-face { + font-family: 'Google Sans'; + font-style: normal; + font-weight: 400; + font-display: swap; + src: url('/fonts/google-sans/22-4UasrENHsxJlGDuGo1OIlJfC6l_24rlCK1Yo_Iqcsih3SAyH6cAwhX9RPiYUvaYr.woff2') + format('woff2'); + unicode-range: U+02D7, U+0303, U+0331, U+0E01-0E5B, U+200C-200D, U+25CC; +} +/* vietnamese */ +@font-face { + font-family: 'Google Sans'; + font-style: normal; + font-weight: 400; + font-display: swap; + src: url('/fonts/google-sans/23-4UasrENHsxJlGDuGo1OIlJfC6l_24rlCK1Yo_Iqcsih3SAyH6cAwhX9RPj0UvaYr.woff2') + format('woff2'); + unicode-range: + U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, + U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB; +} +/* latin-ext */ +@font-face { + font-family: 'Google Sans'; + font-style: normal; + font-weight: 400; + font-display: swap; + src: url('/fonts/google-sans/24-4UasrENHsxJlGDuGo1OIlJfC6l_24rlCK1Yo_Iqcsih3SAyH6cAwhX9RPjwUvaYr.woff2') + format('woff2'); + unicode-range: + U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, + U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, + U+A720-A7FF; +} +/* latin */ +@font-face { + font-family: 'Google Sans'; + font-style: normal; + font-weight: 400; + font-display: swap; + src: url('/fonts/google-sans/25-4UasrENHsxJlGDuGo1OIlJfC6l_24rlCK1Yo_Iqcsih3SAyH6cAwhX9RPjIUvQ.woff2') + format('woff2'); + unicode-range: + U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, + U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; +} +/* armenian */ +@font-face { + font-family: 'Google Sans'; + font-style: normal; + font-weight: 500; + font-display: swap; + src: url('/fonts/google-sans/01-4UasrENHsxJlGDuGo1OIlJfC6l_24rlCK1Yo_Iqcsih3SAyH6cAwhX9RPiIUvaYr.woff2') + format('woff2'); + unicode-range: U+0308, U+0530-058F, U+2010, U+2024, U+25CC, U+FB13-FB17; +} +/* bengali */ +@font-face { + font-family: 'Google Sans'; + font-style: normal; + font-weight: 500; + font-display: swap; + src: url('/fonts/google-sans/02-4UasrENHsxJlGDuGo1OIlJfC6l_24rlCK1Yo_Iqcsih3SAyH6cAwhX9RPiAUvaYr.woff2') + format('woff2'); + unicode-range: + U+0951-0952, U+0964-0965, U+0980-09FE, U+1CD0, U+1CD2, U+1CD5-1CD6, U+1CD8, U+1CE1, U+1CEA, + U+1CED, U+1CF2, U+1CF5-1CF7, U+200C-200D, U+20B9, U+25CC, U+A8F1; +} +/* canadian-aboriginal */ +@font-face { + font-family: 'Google Sans'; + font-style: normal; + font-weight: 500; + font-display: swap; + src: url('/fonts/google-sans/03-4UasrENHsxJlGDuGo1OIlJfC6l_24rlCK1Yo_Iqcsih3SAyH6cAwhX9RPh0UvaYr.woff2') + format('woff2'); + unicode-range: + U+02C7, U+02D8-02D9, U+02DB, U+0307, U+1400-167F, U+18B0-18F5, U+25CC, U+11AB0-11ABF; +} +/* cyrillic-ext */ +@font-face { + font-family: 'Google Sans'; + font-style: normal; + font-weight: 500; + font-display: swap; + src: url('/fonts/google-sans/04-4UasrENHsxJlGDuGo1OIlJfC6l_24rlCK1Yo_Iqcsih3SAyH6cAwhX9RPj8UvaYr.woff2') + format('woff2'); + unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; +} +/* cyrillic */ +@font-face { + font-family: 'Google Sans'; + font-style: normal; + font-weight: 500; + font-display: swap; + src: url('/fonts/google-sans/05-4UasrENHsxJlGDuGo1OIlJfC6l_24rlCK1Yo_Iqcsih3SAyH6cAwhX9RPjYUvaYr.woff2') + format('woff2'); + unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; +} +/* devanagari */ +@font-face { + font-family: 'Google Sans'; + font-style: normal; + font-weight: 500; + font-display: swap; + src: url('/fonts/google-sans/06-4UasrENHsxJlGDuGo1OIlJfC6l_24rlCK1Yo_Iqcsih3SAyH6cAwhX9RPjMUvaYr.woff2') + format('woff2'); + unicode-range: + U+0900-097F, U+1CD0-1CF9, U+200C-200D, U+20A8, U+20B9, U+20F0, U+25CC, U+A830-A839, U+A8E0-A8FF, + U+11B00-11B09; +} +/* ethiopic */ +@font-face { + font-family: 'Google Sans'; + font-style: normal; + font-weight: 500; + font-display: swap; + src: url('/fonts/google-sans/07-4UasrENHsxJlGDuGo1OIlJfC6l_24rlCK1Yo_Iqcsih3SAyH6cAwhX9RPiMUvaYr.woff2') + format('woff2'); + unicode-range: + U+030E, U+1200-1399, U+2D80-2DDE, U+AB01-AB2E, U+1E7E0-1E7E6, U+1E7E8-1E7EB, U+1E7ED-1E7EE, + U+1E7F0-1E7FE; +} +/* georgian */ +@font-face { + font-family: 'Google Sans'; + font-style: normal; + font-weight: 500; + font-display: swap; + src: url('/fonts/google-sans/08-4UasrENHsxJlGDuGo1OIlJfC6l_24rlCK1Yo_Iqcsih3SAyH6cAwhX9RPi0UvaYr.woff2') + format('woff2'); + unicode-range: U+0589, U+10A0-10FF, U+1C90-1CBA, U+1CBD-1CBF, U+205A, U+2D00-2D2F, U+2E31; +} +/* greek-ext */ +@font-face { + font-family: 'Google Sans'; + font-style: normal; + font-weight: 500; + font-display: swap; + src: url('/fonts/google-sans/09-4UasrENHsxJlGDuGo1OIlJfC6l_24rlCK1Yo_Iqcsih3SAyH6cAwhX9RPj4UvaYr.woff2') + format('woff2'); + unicode-range: U+1F00-1FFF; +} +/* greek */ +@font-face { + font-family: 'Google Sans'; + font-style: normal; + font-weight: 500; + font-display: swap; + src: url('/fonts/google-sans/10-4UasrENHsxJlGDuGo1OIlJfC6l_24rlCK1Yo_Iqcsih3SAyH6cAwhX9RPjEUvaYr.woff2') + format('woff2'); + unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF; +} +/* gujarati */ +@font-face { + font-family: 'Google Sans'; + font-style: normal; + font-weight: 500; + font-display: swap; + src: url('/fonts/google-sans/11-4UasrENHsxJlGDuGo1OIlJfC6l_24rlCK1Yo_Iqcsih3SAyH6cAwhX9RPikUvaYr.woff2') + format('woff2'); + unicode-range: U+0951-0952, U+0964-0965, U+0A80-0AFF, U+200C-200D, U+20B9, U+25CC, U+A830-A839; +} +/* gurmukhi */ +@font-face { + font-family: 'Google Sans'; + font-style: normal; + font-weight: 500; + font-display: swap; + src: url('/fonts/google-sans/12-4UasrENHsxJlGDuGo1OIlJfC6l_24rlCK1Yo_Iqcsih3SAyH6cAwhX9RPhEUvaYr.woff2') + format('woff2'); + unicode-range: + U+0951-0952, U+0964-0965, U+0A01-0A76, U+200C-200D, U+20B9, U+25CC, U+262C, U+A830-A839; +} +/* hebrew */ +@font-face { + font-family: 'Google Sans'; + font-style: normal; + font-weight: 500; + font-display: swap; + src: url('/fonts/google-sans/13-4UasrENHsxJlGDuGo1OIlJfC6l_24rlCK1Yo_Iqcsih3SAyH6cAwhX9RPjAUvaYr.woff2') + format('woff2'); + unicode-range: U+0307-0308, U+0590-05FF, U+200C-2010, U+20AA, U+25CC, U+FB1D-FB4F; +} +/* khmer */ +@font-face { + font-family: 'Google Sans'; + font-style: normal; + font-weight: 500; + font-display: swap; + src: url('/fonts/google-sans/14-4UasrENHsxJlGDuGo1OIlJfC6l_24rlCK1Yo_Iqcsih3SAyH6cAwhX9RPjkUvaYr.woff2') + format('woff2'); + unicode-range: U+1780-17FF, U+19E0-19FF, U+200C-200D, U+25CC; +} +/* lao */ +@font-face { + font-family: 'Google Sans'; + font-style: normal; + font-weight: 500; + font-display: swap; + src: url('/fonts/google-sans/15-4UasrENHsxJlGDuGo1OIlJfC6l_24rlCK1Yo_Iqcsih3SAyH6cAwhX9RPjsUvaYr.woff2') + format('woff2'); + unicode-range: U+0E81-0EDF, U+200C-200D, U+25CC; +} +/* malayalam */ +@font-face { + font-family: 'Google Sans'; + font-style: normal; + font-weight: 500; + font-display: swap; + src: url('/fonts/google-sans/16-4UasrENHsxJlGDuGo1OIlJfC6l_24rlCK1Yo_Iqcsih3SAyH6cAwhX9RPioUvaYr.woff2') + format('woff2'); + unicode-range: + U+0307, U+0323, U+0951-0952, U+0964-0965, U+0D00-0D7F, U+1CDA, U+1CF2, U+200C-200D, U+20B9, + U+25CC, U+A830-A832; +} +/* oriya */ +@font-face { + font-family: 'Google Sans'; + font-style: normal; + font-weight: 500; + font-display: swap; + src: url('/fonts/google-sans/17-4UasrENHsxJlGDuGo1OIlJfC6l_24rlCK1Yo_Iqcsih3SAyH6cAwhX9RPisUvaYr.woff2') + format('woff2'); + unicode-range: U+0951-0952, U+0964-0965, U+0B01-0B77, U+1CDA, U+1CF2, U+200C-200D, U+20B9, U+25CC; +} +/* sinhala */ +@font-face { + font-family: 'Google Sans'; + font-style: normal; + font-weight: 500; + font-display: swap; + src: url('/fonts/google-sans/18-4UasrENHsxJlGDuGo1OIlJfC6l_24rlCK1Yo_Iqcsih3SAyH6cAwhX9RPi8UvaYr.woff2') + format('woff2'); + unicode-range: U+0964-0965, U+0D81-0DF4, U+1CF2, U+200C-200D, U+25CC, U+111E1-111F4; +} +/* symbols */ +@font-face { + font-family: 'Google Sans'; + font-style: normal; + font-weight: 500; + font-display: swap; + src: url('/fonts/google-sans/19-4UasrENHsxJlGDuGo1OIlJfC6l_24rlCK1Yo_Iqcsih3SAyH6cAwhX9RPlwUvaYr.woff2') + format('woff2'); + unicode-range: + U+0001-000C, U+000E-001F, U+007F-009F, U+20DD-20E0, U+20E2-20E4, U+2150-218F, U+2190, U+2192, + U+2194-2199, U+21AF, U+21E6-21F0, U+21F3, U+2218-2219, U+2299, U+22C4-22C6, U+2300-243F, + U+2440-244A, U+2460-24FF, U+25A0-27BF, U+2800-28FF, U+2921-2922, U+2981, U+29BF, U+29EB, + U+2B00-2BFF, U+4DC0-4DFF, U+FFF9-FFFB, U+10140-1018E, U+10190-1019C, U+101A0, U+101D0-101FD, + U+102E0-102FB, U+10E60-10E7E, U+1D2C0-1D2D3, U+1D2E0-1D37F, U+1F000-1F0FF, U+1F100-1F1AD, + U+1F1E6-1F1FF, U+1F30D-1F30F, U+1F315, U+1F31C, U+1F31E, U+1F320-1F32C, U+1F336, U+1F378, + U+1F37D, U+1F382, U+1F393-1F39F, U+1F3A7-1F3A8, U+1F3AC-1F3AF, U+1F3C2, U+1F3C4-1F3C6, + U+1F3CA-1F3CE, U+1F3D4-1F3E0, U+1F3ED, U+1F3F1-1F3F3, U+1F3F5-1F3F7, U+1F408, U+1F415, U+1F41F, + U+1F426, U+1F43F, U+1F441-1F442, U+1F444, U+1F446-1F449, U+1F44C-1F44E, U+1F453, U+1F46A, + U+1F47D, U+1F4A3, U+1F4B0, U+1F4B3, U+1F4B9, U+1F4BB, U+1F4BF, U+1F4C8-1F4CB, U+1F4D6, U+1F4DA, + U+1F4DF, U+1F4E3-1F4E6, U+1F4EA-1F4ED, U+1F4F7, U+1F4F9-1F4FB, U+1F4FD-1F4FE, U+1F503, + U+1F507-1F50B, U+1F50D, U+1F512-1F513, U+1F53E-1F54A, U+1F54F-1F5FA, U+1F610, U+1F650-1F67F, + U+1F687, U+1F68D, U+1F691, U+1F694, U+1F698, U+1F6AD, U+1F6B2, U+1F6B9-1F6BA, U+1F6BC, + U+1F6C6-1F6CF, U+1F6D3-1F6D7, U+1F6E0-1F6EA, U+1F6F0-1F6F3, U+1F6F7-1F6FC, U+1F700-1F7FF, + U+1F800-1F80B, U+1F810-1F847, U+1F850-1F859, U+1F860-1F887, U+1F890-1F8AD, U+1F8B0-1F8BB, + U+1F8C0-1F8C1, U+1F900-1F90B, U+1F93B, U+1F946, U+1F984, U+1F996, U+1F9E9, U+1FA00-1FA6F, + U+1FA70-1FA7C, U+1FA80-1FA89, U+1FA8F-1FAC6, U+1FACE-1FADC, U+1FADF-1FAE9, U+1FAF0-1FAF8, + U+1FB00-1FBFF; +} +/* tamil */ +@font-face { + font-family: 'Google Sans'; + font-style: normal; + font-weight: 500; + font-display: swap; + src: url('/fonts/google-sans/20-4UasrENHsxJlGDuGo1OIlJfC6l_24rlCK1Yo_Iqcsih3SAyH6cAwhX9RPiQUvaYr.woff2') + format('woff2'); + unicode-range: U+0964-0965, U+0B82-0BFA, U+200C-200D, U+20B9, U+25CC; +} +/* telugu */ +@font-face { + font-family: 'Google Sans'; + font-style: normal; + font-weight: 500; + font-display: swap; + src: url('/fonts/google-sans/21-4UasrENHsxJlGDuGo1OIlJfC6l_24rlCK1Yo_Iqcsih3SAyH6cAwhX9RPi4UvaYr.woff2') + format('woff2'); + unicode-range: U+0951-0952, U+0964-0965, U+0C00-0C7F, U+1CDA, U+1CF2, U+200C-200D, U+25CC; +} +/* thai */ +@font-face { + font-family: 'Google Sans'; + font-style: normal; + font-weight: 500; + font-display: swap; + src: url('/fonts/google-sans/22-4UasrENHsxJlGDuGo1OIlJfC6l_24rlCK1Yo_Iqcsih3SAyH6cAwhX9RPiYUvaYr.woff2') + format('woff2'); + unicode-range: U+02D7, U+0303, U+0331, U+0E01-0E5B, U+200C-200D, U+25CC; +} +/* vietnamese */ +@font-face { + font-family: 'Google Sans'; + font-style: normal; + font-weight: 500; + font-display: swap; + src: url('/fonts/google-sans/23-4UasrENHsxJlGDuGo1OIlJfC6l_24rlCK1Yo_Iqcsih3SAyH6cAwhX9RPj0UvaYr.woff2') + format('woff2'); + unicode-range: + U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, + U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB; +} +/* latin-ext */ +@font-face { + font-family: 'Google Sans'; + font-style: normal; + font-weight: 500; + font-display: swap; + src: url('/fonts/google-sans/24-4UasrENHsxJlGDuGo1OIlJfC6l_24rlCK1Yo_Iqcsih3SAyH6cAwhX9RPjwUvaYr.woff2') + format('woff2'); + unicode-range: + U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, + U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, + U+A720-A7FF; +} +/* latin */ +@font-face { + font-family: 'Google Sans'; + font-style: normal; + font-weight: 500; + font-display: swap; + src: url('/fonts/google-sans/25-4UasrENHsxJlGDuGo1OIlJfC6l_24rlCK1Yo_Iqcsih3SAyH6cAwhX9RPjIUvQ.woff2') + format('woff2'); + unicode-range: + U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, + U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; +} +/* armenian */ +@font-face { + font-family: 'Google Sans'; + font-style: normal; + font-weight: 700; + font-display: swap; + src: url('/fonts/google-sans/01-4UasrENHsxJlGDuGo1OIlJfC6l_24rlCK1Yo_Iqcsih3SAyH6cAwhX9RPiIUvaYr.woff2') + format('woff2'); + unicode-range: U+0308, U+0530-058F, U+2010, U+2024, U+25CC, U+FB13-FB17; +} +/* bengali */ +@font-face { + font-family: 'Google Sans'; + font-style: normal; + font-weight: 700; + font-display: swap; + src: url('/fonts/google-sans/02-4UasrENHsxJlGDuGo1OIlJfC6l_24rlCK1Yo_Iqcsih3SAyH6cAwhX9RPiAUvaYr.woff2') + format('woff2'); + unicode-range: + U+0951-0952, U+0964-0965, U+0980-09FE, U+1CD0, U+1CD2, U+1CD5-1CD6, U+1CD8, U+1CE1, U+1CEA, + U+1CED, U+1CF2, U+1CF5-1CF7, U+200C-200D, U+20B9, U+25CC, U+A8F1; +} +/* canadian-aboriginal */ +@font-face { + font-family: 'Google Sans'; + font-style: normal; + font-weight: 700; + font-display: swap; + src: url('/fonts/google-sans/03-4UasrENHsxJlGDuGo1OIlJfC6l_24rlCK1Yo_Iqcsih3SAyH6cAwhX9RPh0UvaYr.woff2') + format('woff2'); + unicode-range: + U+02C7, U+02D8-02D9, U+02DB, U+0307, U+1400-167F, U+18B0-18F5, U+25CC, U+11AB0-11ABF; +} +/* cyrillic-ext */ +@font-face { + font-family: 'Google Sans'; + font-style: normal; + font-weight: 700; + font-display: swap; + src: url('/fonts/google-sans/04-4UasrENHsxJlGDuGo1OIlJfC6l_24rlCK1Yo_Iqcsih3SAyH6cAwhX9RPj8UvaYr.woff2') + format('woff2'); + unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; +} +/* cyrillic */ +@font-face { + font-family: 'Google Sans'; + font-style: normal; + font-weight: 700; + font-display: swap; + src: url('/fonts/google-sans/05-4UasrENHsxJlGDuGo1OIlJfC6l_24rlCK1Yo_Iqcsih3SAyH6cAwhX9RPjYUvaYr.woff2') + format('woff2'); + unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; +} +/* devanagari */ +@font-face { + font-family: 'Google Sans'; + font-style: normal; + font-weight: 700; + font-display: swap; + src: url('/fonts/google-sans/06-4UasrENHsxJlGDuGo1OIlJfC6l_24rlCK1Yo_Iqcsih3SAyH6cAwhX9RPjMUvaYr.woff2') + format('woff2'); + unicode-range: + U+0900-097F, U+1CD0-1CF9, U+200C-200D, U+20A8, U+20B9, U+20F0, U+25CC, U+A830-A839, U+A8E0-A8FF, + U+11B00-11B09; +} +/* ethiopic */ +@font-face { + font-family: 'Google Sans'; + font-style: normal; + font-weight: 700; + font-display: swap; + src: url('/fonts/google-sans/07-4UasrENHsxJlGDuGo1OIlJfC6l_24rlCK1Yo_Iqcsih3SAyH6cAwhX9RPiMUvaYr.woff2') + format('woff2'); + unicode-range: + U+030E, U+1200-1399, U+2D80-2DDE, U+AB01-AB2E, U+1E7E0-1E7E6, U+1E7E8-1E7EB, U+1E7ED-1E7EE, + U+1E7F0-1E7FE; +} +/* georgian */ +@font-face { + font-family: 'Google Sans'; + font-style: normal; + font-weight: 700; + font-display: swap; + src: url('/fonts/google-sans/08-4UasrENHsxJlGDuGo1OIlJfC6l_24rlCK1Yo_Iqcsih3SAyH6cAwhX9RPi0UvaYr.woff2') + format('woff2'); + unicode-range: U+0589, U+10A0-10FF, U+1C90-1CBA, U+1CBD-1CBF, U+205A, U+2D00-2D2F, U+2E31; +} +/* greek-ext */ +@font-face { + font-family: 'Google Sans'; + font-style: normal; + font-weight: 700; + font-display: swap; + src: url('/fonts/google-sans/09-4UasrENHsxJlGDuGo1OIlJfC6l_24rlCK1Yo_Iqcsih3SAyH6cAwhX9RPj4UvaYr.woff2') + format('woff2'); + unicode-range: U+1F00-1FFF; +} +/* greek */ +@font-face { + font-family: 'Google Sans'; + font-style: normal; + font-weight: 700; + font-display: swap; + src: url('/fonts/google-sans/10-4UasrENHsxJlGDuGo1OIlJfC6l_24rlCK1Yo_Iqcsih3SAyH6cAwhX9RPjEUvaYr.woff2') + format('woff2'); + unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF; +} +/* gujarati */ +@font-face { + font-family: 'Google Sans'; + font-style: normal; + font-weight: 700; + font-display: swap; + src: url('/fonts/google-sans/11-4UasrENHsxJlGDuGo1OIlJfC6l_24rlCK1Yo_Iqcsih3SAyH6cAwhX9RPikUvaYr.woff2') + format('woff2'); + unicode-range: U+0951-0952, U+0964-0965, U+0A80-0AFF, U+200C-200D, U+20B9, U+25CC, U+A830-A839; +} +/* gurmukhi */ +@font-face { + font-family: 'Google Sans'; + font-style: normal; + font-weight: 700; + font-display: swap; + src: url('/fonts/google-sans/12-4UasrENHsxJlGDuGo1OIlJfC6l_24rlCK1Yo_Iqcsih3SAyH6cAwhX9RPhEUvaYr.woff2') + format('woff2'); + unicode-range: + U+0951-0952, U+0964-0965, U+0A01-0A76, U+200C-200D, U+20B9, U+25CC, U+262C, U+A830-A839; +} +/* hebrew */ +@font-face { + font-family: 'Google Sans'; + font-style: normal; + font-weight: 700; + font-display: swap; + src: url('/fonts/google-sans/13-4UasrENHsxJlGDuGo1OIlJfC6l_24rlCK1Yo_Iqcsih3SAyH6cAwhX9RPjAUvaYr.woff2') + format('woff2'); + unicode-range: U+0307-0308, U+0590-05FF, U+200C-2010, U+20AA, U+25CC, U+FB1D-FB4F; +} +/* khmer */ +@font-face { + font-family: 'Google Sans'; + font-style: normal; + font-weight: 700; + font-display: swap; + src: url('/fonts/google-sans/14-4UasrENHsxJlGDuGo1OIlJfC6l_24rlCK1Yo_Iqcsih3SAyH6cAwhX9RPjkUvaYr.woff2') + format('woff2'); + unicode-range: U+1780-17FF, U+19E0-19FF, U+200C-200D, U+25CC; +} +/* lao */ +@font-face { + font-family: 'Google Sans'; + font-style: normal; + font-weight: 700; + font-display: swap; + src: url('/fonts/google-sans/15-4UasrENHsxJlGDuGo1OIlJfC6l_24rlCK1Yo_Iqcsih3SAyH6cAwhX9RPjsUvaYr.woff2') + format('woff2'); + unicode-range: U+0E81-0EDF, U+200C-200D, U+25CC; +} +/* malayalam */ +@font-face { + font-family: 'Google Sans'; + font-style: normal; + font-weight: 700; + font-display: swap; + src: url('/fonts/google-sans/16-4UasrENHsxJlGDuGo1OIlJfC6l_24rlCK1Yo_Iqcsih3SAyH6cAwhX9RPioUvaYr.woff2') + format('woff2'); + unicode-range: + U+0307, U+0323, U+0951-0952, U+0964-0965, U+0D00-0D7F, U+1CDA, U+1CF2, U+200C-200D, U+20B9, + U+25CC, U+A830-A832; +} +/* oriya */ +@font-face { + font-family: 'Google Sans'; + font-style: normal; + font-weight: 700; + font-display: swap; + src: url('/fonts/google-sans/17-4UasrENHsxJlGDuGo1OIlJfC6l_24rlCK1Yo_Iqcsih3SAyH6cAwhX9RPisUvaYr.woff2') + format('woff2'); + unicode-range: U+0951-0952, U+0964-0965, U+0B01-0B77, U+1CDA, U+1CF2, U+200C-200D, U+20B9, U+25CC; +} +/* sinhala */ +@font-face { + font-family: 'Google Sans'; + font-style: normal; + font-weight: 700; + font-display: swap; + src: url('/fonts/google-sans/18-4UasrENHsxJlGDuGo1OIlJfC6l_24rlCK1Yo_Iqcsih3SAyH6cAwhX9RPi8UvaYr.woff2') + format('woff2'); + unicode-range: U+0964-0965, U+0D81-0DF4, U+1CF2, U+200C-200D, U+25CC, U+111E1-111F4; +} +/* symbols */ +@font-face { + font-family: 'Google Sans'; + font-style: normal; + font-weight: 700; + font-display: swap; + src: url('/fonts/google-sans/19-4UasrENHsxJlGDuGo1OIlJfC6l_24rlCK1Yo_Iqcsih3SAyH6cAwhX9RPlwUvaYr.woff2') + format('woff2'); + unicode-range: + U+0001-000C, U+000E-001F, U+007F-009F, U+20DD-20E0, U+20E2-20E4, U+2150-218F, U+2190, U+2192, + U+2194-2199, U+21AF, U+21E6-21F0, U+21F3, U+2218-2219, U+2299, U+22C4-22C6, U+2300-243F, + U+2440-244A, U+2460-24FF, U+25A0-27BF, U+2800-28FF, U+2921-2922, U+2981, U+29BF, U+29EB, + U+2B00-2BFF, U+4DC0-4DFF, U+FFF9-FFFB, U+10140-1018E, U+10190-1019C, U+101A0, U+101D0-101FD, + U+102E0-102FB, U+10E60-10E7E, U+1D2C0-1D2D3, U+1D2E0-1D37F, U+1F000-1F0FF, U+1F100-1F1AD, + U+1F1E6-1F1FF, U+1F30D-1F30F, U+1F315, U+1F31C, U+1F31E, U+1F320-1F32C, U+1F336, U+1F378, + U+1F37D, U+1F382, U+1F393-1F39F, U+1F3A7-1F3A8, U+1F3AC-1F3AF, U+1F3C2, U+1F3C4-1F3C6, + U+1F3CA-1F3CE, U+1F3D4-1F3E0, U+1F3ED, U+1F3F1-1F3F3, U+1F3F5-1F3F7, U+1F408, U+1F415, U+1F41F, + U+1F426, U+1F43F, U+1F441-1F442, U+1F444, U+1F446-1F449, U+1F44C-1F44E, U+1F453, U+1F46A, + U+1F47D, U+1F4A3, U+1F4B0, U+1F4B3, U+1F4B9, U+1F4BB, U+1F4BF, U+1F4C8-1F4CB, U+1F4D6, U+1F4DA, + U+1F4DF, U+1F4E3-1F4E6, U+1F4EA-1F4ED, U+1F4F7, U+1F4F9-1F4FB, U+1F4FD-1F4FE, U+1F503, + U+1F507-1F50B, U+1F50D, U+1F512-1F513, U+1F53E-1F54A, U+1F54F-1F5FA, U+1F610, U+1F650-1F67F, + U+1F687, U+1F68D, U+1F691, U+1F694, U+1F698, U+1F6AD, U+1F6B2, U+1F6B9-1F6BA, U+1F6BC, + U+1F6C6-1F6CF, U+1F6D3-1F6D7, U+1F6E0-1F6EA, U+1F6F0-1F6F3, U+1F6F7-1F6FC, U+1F700-1F7FF, + U+1F800-1F80B, U+1F810-1F847, U+1F850-1F859, U+1F860-1F887, U+1F890-1F8AD, U+1F8B0-1F8BB, + U+1F8C0-1F8C1, U+1F900-1F90B, U+1F93B, U+1F946, U+1F984, U+1F996, U+1F9E9, U+1FA00-1FA6F, + U+1FA70-1FA7C, U+1FA80-1FA89, U+1FA8F-1FAC6, U+1FACE-1FADC, U+1FADF-1FAE9, U+1FAF0-1FAF8, + U+1FB00-1FBFF; +} +/* tamil */ +@font-face { + font-family: 'Google Sans'; + font-style: normal; + font-weight: 700; + font-display: swap; + src: url('/fonts/google-sans/20-4UasrENHsxJlGDuGo1OIlJfC6l_24rlCK1Yo_Iqcsih3SAyH6cAwhX9RPiQUvaYr.woff2') + format('woff2'); + unicode-range: U+0964-0965, U+0B82-0BFA, U+200C-200D, U+20B9, U+25CC; +} +/* telugu */ +@font-face { + font-family: 'Google Sans'; + font-style: normal; + font-weight: 700; + font-display: swap; + src: url('/fonts/google-sans/21-4UasrENHsxJlGDuGo1OIlJfC6l_24rlCK1Yo_Iqcsih3SAyH6cAwhX9RPi4UvaYr.woff2') + format('woff2'); + unicode-range: U+0951-0952, U+0964-0965, U+0C00-0C7F, U+1CDA, U+1CF2, U+200C-200D, U+25CC; +} +/* thai */ +@font-face { + font-family: 'Google Sans'; + font-style: normal; + font-weight: 700; + font-display: swap; + src: url('/fonts/google-sans/22-4UasrENHsxJlGDuGo1OIlJfC6l_24rlCK1Yo_Iqcsih3SAyH6cAwhX9RPiYUvaYr.woff2') + format('woff2'); + unicode-range: U+02D7, U+0303, U+0331, U+0E01-0E5B, U+200C-200D, U+25CC; +} +/* vietnamese */ +@font-face { + font-family: 'Google Sans'; + font-style: normal; + font-weight: 700; + font-display: swap; + src: url('/fonts/google-sans/23-4UasrENHsxJlGDuGo1OIlJfC6l_24rlCK1Yo_Iqcsih3SAyH6cAwhX9RPj0UvaYr.woff2') + format('woff2'); + unicode-range: + U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, + U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB; +} +/* latin-ext */ +@font-face { + font-family: 'Google Sans'; + font-style: normal; + font-weight: 700; + font-display: swap; + src: url('/fonts/google-sans/24-4UasrENHsxJlGDuGo1OIlJfC6l_24rlCK1Yo_Iqcsih3SAyH6cAwhX9RPjwUvaYr.woff2') + format('woff2'); + unicode-range: + U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, + U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, + U+A720-A7FF; +} +/* latin */ +@font-face { + font-family: 'Google Sans'; + font-style: normal; + font-weight: 700; + font-display: swap; + src: url('/fonts/google-sans/25-4UasrENHsxJlGDuGo1OIlJfC6l_24rlCK1Yo_Iqcsih3SAyH6cAwhX9RPjIUvQ.woff2') + format('woff2'); + unicode-range: + U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, + U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; +} +/* canadian-aboriginal */ +@font-face { + font-family: 'Google Sans Flex'; + font-style: normal; + font-weight: 400; + font-stretch: 100%; + font-display: swap; + src: url('/fonts/google-sans/26-t5s6IQcYNIWbFgDgAAzZ34auoVyXkJCOvp3SFWJbN5hF8Ju1x6sKCyp0l9sI40swNJwInycYAJzz0m7kJ4qFQOJBOjLvDSndo0SKMpKSTzwliVdHAy4x5hg2a2c.woff2') + format('woff2'); + unicode-range: + U+02C7, U+02D8-02D9, U+02DB, U+0307, U+1400-167F, U+18B0-18F5, U+25CC, U+11AB0-11ABF; +} +/* cherokee */ +@font-face { + font-family: 'Google Sans Flex'; + font-style: normal; + font-weight: 400; + font-stretch: 100%; + font-display: swap; + src: url('/fonts/google-sans/27-t5s6IQcYNIWbFgDgAAzZ34auoVyXkJCOvp3SFWJbN5hF8Ju1x6sKCyp0l9sI40swNJwInycYAJzz0m7kJ4qFQOJBOjLvDSndo0SKMpKSTzwliVdHAy4x2hg2a2c.woff2') + format('woff2'); + unicode-range: + U+0300-0302, U+0304, U+030B-030C, U+0323-0324, U+0330-0331, U+13A0-13FF, U+AB70-ABBF; +} +/* math */ +@font-face { + font-family: 'Google Sans Flex'; + font-style: normal; + font-weight: 400; + font-stretch: 100%; + font-display: swap; + src: url('/fonts/google-sans/28-t5s6IQcYNIWbFgDgAAzZ34auoVyXkJCOvp3SFWJbN5hF8Ju1x6sKCyp0l9sI40swNJwInycYAJzz0m7kJ4qFQOJBOjLvDSndo0SKMpKSTzwliVdHAy4xtRg2a2c.woff2') + format('woff2'); + unicode-range: + U+0302-0303, U+0305, U+0307-0308, U+0310, U+0312, U+0315, U+031A, U+0326-0327, U+032C, + U+032F-0330, U+0332-0333, U+0338, U+033A, U+0346, U+034D, U+0391-03A1, U+03A3-03A9, U+03B1-03C9, + U+03D1, U+03D5-03D6, U+03F0-03F1, U+03F4-03F5, U+2016-2017, U+2034-2038, U+203C, U+2040, U+2043, + U+2047, U+2050, U+2057, U+205F, U+2070-2071, U+2074-208E, U+2090-209C, U+20D0-20DC, U+20E1, + U+20E5-20EF, U+2100-2112, U+2114-2115, U+2117-2121, U+2123-214F, U+2190, U+2192, U+2194-21AE, + U+21B0-21E5, U+21F1-21F2, U+21F4-2211, U+2213-2214, U+2216-22FF, U+2308-230B, U+2310, U+2319, + U+231C-2321, U+2336-237A, U+237C, U+2395, U+239B-23B7, U+23D0, U+23DC-23E1, U+2474-2475, U+25AF, + U+25B3, U+25B7, U+25BD, U+25C1, U+25CA, U+25CC, U+25FB, U+266D-266F, U+27C0-27FF, U+2900-2AFF, + U+2B0E-2B11, U+2B30-2B4C, U+2BFE, U+3030, U+FF5B, U+FF5D, U+1D400-1D7FF, U+1EE00-1EEFF; +} +/* nushu */ +@font-face { + font-family: 'Google Sans Flex'; + font-style: normal; + font-weight: 400; + font-stretch: 100%; + font-display: swap; + src: url('/fonts/google-sans/29-t5s6IQcYNIWbFgDgAAzZ34auoVyXkJCOvp3SFWJbN5hF8Ju1x6sKCyp0l9sI40swNJwInycYAJzz0m7kJ4qFQOJBOjLvDSndo0SKMpKSTzwliVdHAy4xthg2a2c.woff2') + format('woff2'); + unicode-range: U+2003, U+3000, U+3002, U+4E00, U+FE12, U+16FE1, U+1B170-1B2FB; +} +/* symbols */ +@font-face { + font-family: 'Google Sans Flex'; + font-style: normal; + font-weight: 400; + font-stretch: 100%; + font-display: swap; + src: url('/fonts/google-sans/30-t5s6IQcYNIWbFgDgAAzZ34auoVyXkJCOvp3SFWJbN5hF8Ju1x6sKCyp0l9sI40swNJwInycYAJzz0m7kJ4qFQOJBOjLvDSndo0SKMpKSTzwliVdHAy4xpxg2a2c.woff2') + format('woff2'); + unicode-range: + U+0001-000C, U+000E-001F, U+007F-009F, U+20DD-20E0, U+20E2-20E4, U+2150-218F, U+2190, U+2192, + U+2194-2199, U+21AF, U+21E6-21F0, U+21F3, U+2218-2219, U+2299, U+22C4-22C6, U+2300-243F, + U+2440-244A, U+2460-24FF, U+25A0-27BF, U+2800-28FF, U+2921-2922, U+2981, U+29BF, U+29EB, + U+2B00-2BFF, U+4DC0-4DFF, U+FFF9-FFFB, U+10140-1018E, U+10190-1019C, U+101A0, U+101D0-101FD, + U+102E0-102FB, U+10E60-10E7E, U+1D2C0-1D2D3, U+1D2E0-1D37F, U+1F000-1F0FF, U+1F100-1F1AD, + U+1F1E6-1F1FF, U+1F30D-1F30F, U+1F315, U+1F31C, U+1F31E, U+1F320-1F32C, U+1F336, U+1F378, + U+1F37D, U+1F382, U+1F393-1F39F, U+1F3A7-1F3A8, U+1F3AC-1F3AF, U+1F3C2, U+1F3C4-1F3C6, + U+1F3CA-1F3CE, U+1F3D4-1F3E0, U+1F3ED, U+1F3F1-1F3F3, U+1F3F5-1F3F7, U+1F408, U+1F415, U+1F41F, + U+1F426, U+1F43F, U+1F441-1F442, U+1F444, U+1F446-1F449, U+1F44C-1F44E, U+1F453, U+1F46A, + U+1F47D, U+1F4A3, U+1F4B0, U+1F4B3, U+1F4B9, U+1F4BB, U+1F4BF, U+1F4C8-1F4CB, U+1F4D6, U+1F4DA, + U+1F4DF, U+1F4E3-1F4E6, U+1F4EA-1F4ED, U+1F4F7, U+1F4F9-1F4FB, U+1F4FD-1F4FE, U+1F503, + U+1F507-1F50B, U+1F50D, U+1F512-1F513, U+1F53E-1F54A, U+1F54F-1F5FA, U+1F610, U+1F650-1F67F, + U+1F687, U+1F68D, U+1F691, U+1F694, U+1F698, U+1F6AD, U+1F6B2, U+1F6B9-1F6BA, U+1F6BC, + U+1F6C6-1F6CF, U+1F6D3-1F6D7, U+1F6E0-1F6EA, U+1F6F0-1F6F3, U+1F6F7-1F6FC, U+1F700-1F7FF, + U+1F800-1F80B, U+1F810-1F847, U+1F850-1F859, U+1F860-1F887, U+1F890-1F8AD, U+1F8B0-1F8BB, + U+1F8C0-1F8C1, U+1F900-1F90B, U+1F93B, U+1F946, U+1F984, U+1F996, U+1F9E9, U+1FA00-1FA6F, + U+1FA70-1FA7C, U+1FA80-1FA89, U+1FA8F-1FAC6, U+1FACE-1FADC, U+1FADF-1FAE9, U+1FAF0-1FAF8, + U+1FB00-1FBFF; +} +/* syriac */ +@font-face { + font-family: 'Google Sans Flex'; + font-style: normal; + font-weight: 400; + font-stretch: 100%; + font-display: swap; + src: url('/fonts/google-sans/31-t5s6IQcYNIWbFgDgAAzZ34auoVyXkJCOvp3SFWJbN5hF8Ju1x6sKCyp0l9sI40swNJwInycYAJzz0m7kJ4qFQOJBOjLvDSndo0SKMpKSTzwliVdHAy4xuhg2a2c.woff2') + format('woff2'); + unicode-range: + U+0303-0304, U+0307-0308, U+030A, U+0320, U+0323-0325, U+032D-032E, U+0330-0331, U+060C, + U+061B-061C, U+061F, U+0621, U+0640, U+064B-0655, U+0660-066C, U+0670, U+0700-074F, U+0860-086A, + U+1DF8, U+1DFA, U+200C-200F, U+25CC, U+2670-2671; +} +/* tifinagh */ +@font-face { + font-family: 'Google Sans Flex'; + font-style: normal; + font-weight: 400; + font-stretch: 100%; + font-display: swap; + src: url('/fonts/google-sans/32-t5s6IQcYNIWbFgDgAAzZ34auoVyXkJCOvp3SFWJbN5hF8Ju1x6sKCyp0l9sI40swNJwInycYAJzz0m7kJ4qFQOJBOjLvDSndo0SKMpKSTzwliVdHAy4x6Rg2a2c.woff2') + format('woff2'); + unicode-range: + U+02C7, U+0301-0302, U+0304, U+0306-0307, U+0309, U+0323, U+0331, U+200C-200D, U+202E, U+25CC, + U+2D30-2D7F; +} +/* vietnamese */ +@font-face { + font-family: 'Google Sans Flex'; + font-style: normal; + font-weight: 400; + font-stretch: 100%; + font-display: swap; + src: url('/fonts/google-sans/33-t5s6IQcYNIWbFgDgAAzZ34auoVyXkJCOvp3SFWJbN5hF8Ju1x6sKCyp0l9sI40swNJwInycYAJzz0m7kJ4qFQOJBOjLvDSndo0SKMpKSTzwliVdHAy4xxhg2a2c.woff2') + format('woff2'); + unicode-range: + U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, + U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB; +} +/* latin-ext */ +@font-face { + font-family: 'Google Sans Flex'; + font-style: normal; + font-weight: 400; + font-stretch: 100%; + font-display: swap; + src: url('/fonts/google-sans/34-t5s6IQcYNIWbFgDgAAzZ34auoVyXkJCOvp3SFWJbN5hF8Ju1x6sKCyp0l9sI40swNJwInycYAJzz0m7kJ4qFQOJBOjLvDSndo0SKMpKSTzwliVdHAy4xxxg2a2c.woff2') + format('woff2'); + unicode-range: + U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, + U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, + U+A720-A7FF; +} +/* latin */ +@font-face { + font-family: 'Google Sans Flex'; + font-style: normal; + font-weight: 400; + font-stretch: 100%; + font-display: swap; + src: url('/fonts/google-sans/35-t5s6IQcYNIWbFgDgAAzZ34auoVyXkJCOvp3SFWJbN5hF8Ju1x6sKCyp0l9sI40swNJwInycYAJzz0m7kJ4qFQOJBOjLvDSndo0SKMpKSTzwliVdHAy4xyRg2.woff2') + format('woff2'); + unicode-range: + U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, + U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; +} +/* canadian-aboriginal */ +@font-face { + font-family: 'Google Sans Flex'; + font-style: normal; + font-weight: 500; + font-stretch: 100%; + font-display: swap; + src: url('/fonts/google-sans/26-t5s6IQcYNIWbFgDgAAzZ34auoVyXkJCOvp3SFWJbN5hF8Ju1x6sKCyp0l9sI40swNJwInycYAJzz0m7kJ4qFQOJBOjLvDSndo0SKMpKSTzwliVdHAy4x5hg2a2c.woff2') + format('woff2'); + unicode-range: + U+02C7, U+02D8-02D9, U+02DB, U+0307, U+1400-167F, U+18B0-18F5, U+25CC, U+11AB0-11ABF; +} +/* cherokee */ +@font-face { + font-family: 'Google Sans Flex'; + font-style: normal; + font-weight: 500; + font-stretch: 100%; + font-display: swap; + src: url('/fonts/google-sans/27-t5s6IQcYNIWbFgDgAAzZ34auoVyXkJCOvp3SFWJbN5hF8Ju1x6sKCyp0l9sI40swNJwInycYAJzz0m7kJ4qFQOJBOjLvDSndo0SKMpKSTzwliVdHAy4x2hg2a2c.woff2') + format('woff2'); + unicode-range: + U+0300-0302, U+0304, U+030B-030C, U+0323-0324, U+0330-0331, U+13A0-13FF, U+AB70-ABBF; +} +/* math */ +@font-face { + font-family: 'Google Sans Flex'; + font-style: normal; + font-weight: 500; + font-stretch: 100%; + font-display: swap; + src: url('/fonts/google-sans/28-t5s6IQcYNIWbFgDgAAzZ34auoVyXkJCOvp3SFWJbN5hF8Ju1x6sKCyp0l9sI40swNJwInycYAJzz0m7kJ4qFQOJBOjLvDSndo0SKMpKSTzwliVdHAy4xtRg2a2c.woff2') + format('woff2'); + unicode-range: + U+0302-0303, U+0305, U+0307-0308, U+0310, U+0312, U+0315, U+031A, U+0326-0327, U+032C, + U+032F-0330, U+0332-0333, U+0338, U+033A, U+0346, U+034D, U+0391-03A1, U+03A3-03A9, U+03B1-03C9, + U+03D1, U+03D5-03D6, U+03F0-03F1, U+03F4-03F5, U+2016-2017, U+2034-2038, U+203C, U+2040, U+2043, + U+2047, U+2050, U+2057, U+205F, U+2070-2071, U+2074-208E, U+2090-209C, U+20D0-20DC, U+20E1, + U+20E5-20EF, U+2100-2112, U+2114-2115, U+2117-2121, U+2123-214F, U+2190, U+2192, U+2194-21AE, + U+21B0-21E5, U+21F1-21F2, U+21F4-2211, U+2213-2214, U+2216-22FF, U+2308-230B, U+2310, U+2319, + U+231C-2321, U+2336-237A, U+237C, U+2395, U+239B-23B7, U+23D0, U+23DC-23E1, U+2474-2475, U+25AF, + U+25B3, U+25B7, U+25BD, U+25C1, U+25CA, U+25CC, U+25FB, U+266D-266F, U+27C0-27FF, U+2900-2AFF, + U+2B0E-2B11, U+2B30-2B4C, U+2BFE, U+3030, U+FF5B, U+FF5D, U+1D400-1D7FF, U+1EE00-1EEFF; +} +/* nushu */ +@font-face { + font-family: 'Google Sans Flex'; + font-style: normal; + font-weight: 500; + font-stretch: 100%; + font-display: swap; + src: url('/fonts/google-sans/29-t5s6IQcYNIWbFgDgAAzZ34auoVyXkJCOvp3SFWJbN5hF8Ju1x6sKCyp0l9sI40swNJwInycYAJzz0m7kJ4qFQOJBOjLvDSndo0SKMpKSTzwliVdHAy4xthg2a2c.woff2') + format('woff2'); + unicode-range: U+2003, U+3000, U+3002, U+4E00, U+FE12, U+16FE1, U+1B170-1B2FB; +} +/* symbols */ +@font-face { + font-family: 'Google Sans Flex'; + font-style: normal; + font-weight: 500; + font-stretch: 100%; + font-display: swap; + src: url('/fonts/google-sans/30-t5s6IQcYNIWbFgDgAAzZ34auoVyXkJCOvp3SFWJbN5hF8Ju1x6sKCyp0l9sI40swNJwInycYAJzz0m7kJ4qFQOJBOjLvDSndo0SKMpKSTzwliVdHAy4xpxg2a2c.woff2') + format('woff2'); + unicode-range: + U+0001-000C, U+000E-001F, U+007F-009F, U+20DD-20E0, U+20E2-20E4, U+2150-218F, U+2190, U+2192, + U+2194-2199, U+21AF, U+21E6-21F0, U+21F3, U+2218-2219, U+2299, U+22C4-22C6, U+2300-243F, + U+2440-244A, U+2460-24FF, U+25A0-27BF, U+2800-28FF, U+2921-2922, U+2981, U+29BF, U+29EB, + U+2B00-2BFF, U+4DC0-4DFF, U+FFF9-FFFB, U+10140-1018E, U+10190-1019C, U+101A0, U+101D0-101FD, + U+102E0-102FB, U+10E60-10E7E, U+1D2C0-1D2D3, U+1D2E0-1D37F, U+1F000-1F0FF, U+1F100-1F1AD, + U+1F1E6-1F1FF, U+1F30D-1F30F, U+1F315, U+1F31C, U+1F31E, U+1F320-1F32C, U+1F336, U+1F378, + U+1F37D, U+1F382, U+1F393-1F39F, U+1F3A7-1F3A8, U+1F3AC-1F3AF, U+1F3C2, U+1F3C4-1F3C6, + U+1F3CA-1F3CE, U+1F3D4-1F3E0, U+1F3ED, U+1F3F1-1F3F3, U+1F3F5-1F3F7, U+1F408, U+1F415, U+1F41F, + U+1F426, U+1F43F, U+1F441-1F442, U+1F444, U+1F446-1F449, U+1F44C-1F44E, U+1F453, U+1F46A, + U+1F47D, U+1F4A3, U+1F4B0, U+1F4B3, U+1F4B9, U+1F4BB, U+1F4BF, U+1F4C8-1F4CB, U+1F4D6, U+1F4DA, + U+1F4DF, U+1F4E3-1F4E6, U+1F4EA-1F4ED, U+1F4F7, U+1F4F9-1F4FB, U+1F4FD-1F4FE, U+1F503, + U+1F507-1F50B, U+1F50D, U+1F512-1F513, U+1F53E-1F54A, U+1F54F-1F5FA, U+1F610, U+1F650-1F67F, + U+1F687, U+1F68D, U+1F691, U+1F694, U+1F698, U+1F6AD, U+1F6B2, U+1F6B9-1F6BA, U+1F6BC, + U+1F6C6-1F6CF, U+1F6D3-1F6D7, U+1F6E0-1F6EA, U+1F6F0-1F6F3, U+1F6F7-1F6FC, U+1F700-1F7FF, + U+1F800-1F80B, U+1F810-1F847, U+1F850-1F859, U+1F860-1F887, U+1F890-1F8AD, U+1F8B0-1F8BB, + U+1F8C0-1F8C1, U+1F900-1F90B, U+1F93B, U+1F946, U+1F984, U+1F996, U+1F9E9, U+1FA00-1FA6F, + U+1FA70-1FA7C, U+1FA80-1FA89, U+1FA8F-1FAC6, U+1FACE-1FADC, U+1FADF-1FAE9, U+1FAF0-1FAF8, + U+1FB00-1FBFF; +} +/* syriac */ +@font-face { + font-family: 'Google Sans Flex'; + font-style: normal; + font-weight: 500; + font-stretch: 100%; + font-display: swap; + src: url('/fonts/google-sans/31-t5s6IQcYNIWbFgDgAAzZ34auoVyXkJCOvp3SFWJbN5hF8Ju1x6sKCyp0l9sI40swNJwInycYAJzz0m7kJ4qFQOJBOjLvDSndo0SKMpKSTzwliVdHAy4xuhg2a2c.woff2') + format('woff2'); + unicode-range: + U+0303-0304, U+0307-0308, U+030A, U+0320, U+0323-0325, U+032D-032E, U+0330-0331, U+060C, + U+061B-061C, U+061F, U+0621, U+0640, U+064B-0655, U+0660-066C, U+0670, U+0700-074F, U+0860-086A, + U+1DF8, U+1DFA, U+200C-200F, U+25CC, U+2670-2671; +} +/* tifinagh */ +@font-face { + font-family: 'Google Sans Flex'; + font-style: normal; + font-weight: 500; + font-stretch: 100%; + font-display: swap; + src: url('/fonts/google-sans/32-t5s6IQcYNIWbFgDgAAzZ34auoVyXkJCOvp3SFWJbN5hF8Ju1x6sKCyp0l9sI40swNJwInycYAJzz0m7kJ4qFQOJBOjLvDSndo0SKMpKSTzwliVdHAy4x6Rg2a2c.woff2') + format('woff2'); + unicode-range: + U+02C7, U+0301-0302, U+0304, U+0306-0307, U+0309, U+0323, U+0331, U+200C-200D, U+202E, U+25CC, + U+2D30-2D7F; +} +/* vietnamese */ +@font-face { + font-family: 'Google Sans Flex'; + font-style: normal; + font-weight: 500; + font-stretch: 100%; + font-display: swap; + src: url('/fonts/google-sans/33-t5s6IQcYNIWbFgDgAAzZ34auoVyXkJCOvp3SFWJbN5hF8Ju1x6sKCyp0l9sI40swNJwInycYAJzz0m7kJ4qFQOJBOjLvDSndo0SKMpKSTzwliVdHAy4xxhg2a2c.woff2') + format('woff2'); + unicode-range: + U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, + U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB; +} +/* latin-ext */ +@font-face { + font-family: 'Google Sans Flex'; + font-style: normal; + font-weight: 500; + font-stretch: 100%; + font-display: swap; + src: url('/fonts/google-sans/34-t5s6IQcYNIWbFgDgAAzZ34auoVyXkJCOvp3SFWJbN5hF8Ju1x6sKCyp0l9sI40swNJwInycYAJzz0m7kJ4qFQOJBOjLvDSndo0SKMpKSTzwliVdHAy4xxxg2a2c.woff2') + format('woff2'); + unicode-range: + U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, + U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, + U+A720-A7FF; +} +/* latin */ +@font-face { + font-family: 'Google Sans Flex'; + font-style: normal; + font-weight: 500; + font-stretch: 100%; + font-display: swap; + src: url('/fonts/google-sans/35-t5s6IQcYNIWbFgDgAAzZ34auoVyXkJCOvp3SFWJbN5hF8Ju1x6sKCyp0l9sI40swNJwInycYAJzz0m7kJ4qFQOJBOjLvDSndo0SKMpKSTzwliVdHAy4xyRg2.woff2') + format('woff2'); + unicode-range: + U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, + U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; +} +/* canadian-aboriginal */ +@font-face { + font-family: 'Google Sans Flex'; + font-style: normal; + font-weight: 700; + font-stretch: 100%; + font-display: swap; + src: url('/fonts/google-sans/26-t5s6IQcYNIWbFgDgAAzZ34auoVyXkJCOvp3SFWJbN5hF8Ju1x6sKCyp0l9sI40swNJwInycYAJzz0m7kJ4qFQOJBOjLvDSndo0SKMpKSTzwliVdHAy4x5hg2a2c.woff2') + format('woff2'); + unicode-range: + U+02C7, U+02D8-02D9, U+02DB, U+0307, U+1400-167F, U+18B0-18F5, U+25CC, U+11AB0-11ABF; +} +/* cherokee */ +@font-face { + font-family: 'Google Sans Flex'; + font-style: normal; + font-weight: 700; + font-stretch: 100%; + font-display: swap; + src: url('/fonts/google-sans/27-t5s6IQcYNIWbFgDgAAzZ34auoVyXkJCOvp3SFWJbN5hF8Ju1x6sKCyp0l9sI40swNJwInycYAJzz0m7kJ4qFQOJBOjLvDSndo0SKMpKSTzwliVdHAy4x2hg2a2c.woff2') + format('woff2'); + unicode-range: + U+0300-0302, U+0304, U+030B-030C, U+0323-0324, U+0330-0331, U+13A0-13FF, U+AB70-ABBF; +} +/* math */ +@font-face { + font-family: 'Google Sans Flex'; + font-style: normal; + font-weight: 700; + font-stretch: 100%; + font-display: swap; + src: url('/fonts/google-sans/28-t5s6IQcYNIWbFgDgAAzZ34auoVyXkJCOvp3SFWJbN5hF8Ju1x6sKCyp0l9sI40swNJwInycYAJzz0m7kJ4qFQOJBOjLvDSndo0SKMpKSTzwliVdHAy4xtRg2a2c.woff2') + format('woff2'); + unicode-range: + U+0302-0303, U+0305, U+0307-0308, U+0310, U+0312, U+0315, U+031A, U+0326-0327, U+032C, + U+032F-0330, U+0332-0333, U+0338, U+033A, U+0346, U+034D, U+0391-03A1, U+03A3-03A9, U+03B1-03C9, + U+03D1, U+03D5-03D6, U+03F0-03F1, U+03F4-03F5, U+2016-2017, U+2034-2038, U+203C, U+2040, U+2043, + U+2047, U+2050, U+2057, U+205F, U+2070-2071, U+2074-208E, U+2090-209C, U+20D0-20DC, U+20E1, + U+20E5-20EF, U+2100-2112, U+2114-2115, U+2117-2121, U+2123-214F, U+2190, U+2192, U+2194-21AE, + U+21B0-21E5, U+21F1-21F2, U+21F4-2211, U+2213-2214, U+2216-22FF, U+2308-230B, U+2310, U+2319, + U+231C-2321, U+2336-237A, U+237C, U+2395, U+239B-23B7, U+23D0, U+23DC-23E1, U+2474-2475, U+25AF, + U+25B3, U+25B7, U+25BD, U+25C1, U+25CA, U+25CC, U+25FB, U+266D-266F, U+27C0-27FF, U+2900-2AFF, + U+2B0E-2B11, U+2B30-2B4C, U+2BFE, U+3030, U+FF5B, U+FF5D, U+1D400-1D7FF, U+1EE00-1EEFF; +} +/* nushu */ +@font-face { + font-family: 'Google Sans Flex'; + font-style: normal; + font-weight: 700; + font-stretch: 100%; + font-display: swap; + src: url('/fonts/google-sans/29-t5s6IQcYNIWbFgDgAAzZ34auoVyXkJCOvp3SFWJbN5hF8Ju1x6sKCyp0l9sI40swNJwInycYAJzz0m7kJ4qFQOJBOjLvDSndo0SKMpKSTzwliVdHAy4xthg2a2c.woff2') + format('woff2'); + unicode-range: U+2003, U+3000, U+3002, U+4E00, U+FE12, U+16FE1, U+1B170-1B2FB; +} +/* symbols */ +@font-face { + font-family: 'Google Sans Flex'; + font-style: normal; + font-weight: 700; + font-stretch: 100%; + font-display: swap; + src: url('/fonts/google-sans/30-t5s6IQcYNIWbFgDgAAzZ34auoVyXkJCOvp3SFWJbN5hF8Ju1x6sKCyp0l9sI40swNJwInycYAJzz0m7kJ4qFQOJBOjLvDSndo0SKMpKSTzwliVdHAy4xpxg2a2c.woff2') + format('woff2'); + unicode-range: + U+0001-000C, U+000E-001F, U+007F-009F, U+20DD-20E0, U+20E2-20E4, U+2150-218F, U+2190, U+2192, + U+2194-2199, U+21AF, U+21E6-21F0, U+21F3, U+2218-2219, U+2299, U+22C4-22C6, U+2300-243F, + U+2440-244A, U+2460-24FF, U+25A0-27BF, U+2800-28FF, U+2921-2922, U+2981, U+29BF, U+29EB, + U+2B00-2BFF, U+4DC0-4DFF, U+FFF9-FFFB, U+10140-1018E, U+10190-1019C, U+101A0, U+101D0-101FD, + U+102E0-102FB, U+10E60-10E7E, U+1D2C0-1D2D3, U+1D2E0-1D37F, U+1F000-1F0FF, U+1F100-1F1AD, + U+1F1E6-1F1FF, U+1F30D-1F30F, U+1F315, U+1F31C, U+1F31E, U+1F320-1F32C, U+1F336, U+1F378, + U+1F37D, U+1F382, U+1F393-1F39F, U+1F3A7-1F3A8, U+1F3AC-1F3AF, U+1F3C2, U+1F3C4-1F3C6, + U+1F3CA-1F3CE, U+1F3D4-1F3E0, U+1F3ED, U+1F3F1-1F3F3, U+1F3F5-1F3F7, U+1F408, U+1F415, U+1F41F, + U+1F426, U+1F43F, U+1F441-1F442, U+1F444, U+1F446-1F449, U+1F44C-1F44E, U+1F453, U+1F46A, + U+1F47D, U+1F4A3, U+1F4B0, U+1F4B3, U+1F4B9, U+1F4BB, U+1F4BF, U+1F4C8-1F4CB, U+1F4D6, U+1F4DA, + U+1F4DF, U+1F4E3-1F4E6, U+1F4EA-1F4ED, U+1F4F7, U+1F4F9-1F4FB, U+1F4FD-1F4FE, U+1F503, + U+1F507-1F50B, U+1F50D, U+1F512-1F513, U+1F53E-1F54A, U+1F54F-1F5FA, U+1F610, U+1F650-1F67F, + U+1F687, U+1F68D, U+1F691, U+1F694, U+1F698, U+1F6AD, U+1F6B2, U+1F6B9-1F6BA, U+1F6BC, + U+1F6C6-1F6CF, U+1F6D3-1F6D7, U+1F6E0-1F6EA, U+1F6F0-1F6F3, U+1F6F7-1F6FC, U+1F700-1F7FF, + U+1F800-1F80B, U+1F810-1F847, U+1F850-1F859, U+1F860-1F887, U+1F890-1F8AD, U+1F8B0-1F8BB, + U+1F8C0-1F8C1, U+1F900-1F90B, U+1F93B, U+1F946, U+1F984, U+1F996, U+1F9E9, U+1FA00-1FA6F, + U+1FA70-1FA7C, U+1FA80-1FA89, U+1FA8F-1FAC6, U+1FACE-1FADC, U+1FADF-1FAE9, U+1FAF0-1FAF8, + U+1FB00-1FBFF; +} +/* syriac */ +@font-face { + font-family: 'Google Sans Flex'; + font-style: normal; + font-weight: 700; + font-stretch: 100%; + font-display: swap; + src: url('/fonts/google-sans/31-t5s6IQcYNIWbFgDgAAzZ34auoVyXkJCOvp3SFWJbN5hF8Ju1x6sKCyp0l9sI40swNJwInycYAJzz0m7kJ4qFQOJBOjLvDSndo0SKMpKSTzwliVdHAy4xuhg2a2c.woff2') + format('woff2'); + unicode-range: + U+0303-0304, U+0307-0308, U+030A, U+0320, U+0323-0325, U+032D-032E, U+0330-0331, U+060C, + U+061B-061C, U+061F, U+0621, U+0640, U+064B-0655, U+0660-066C, U+0670, U+0700-074F, U+0860-086A, + U+1DF8, U+1DFA, U+200C-200F, U+25CC, U+2670-2671; +} +/* tifinagh */ +@font-face { + font-family: 'Google Sans Flex'; + font-style: normal; + font-weight: 700; + font-stretch: 100%; + font-display: swap; + src: url('/fonts/google-sans/32-t5s6IQcYNIWbFgDgAAzZ34auoVyXkJCOvp3SFWJbN5hF8Ju1x6sKCyp0l9sI40swNJwInycYAJzz0m7kJ4qFQOJBOjLvDSndo0SKMpKSTzwliVdHAy4x6Rg2a2c.woff2') + format('woff2'); + unicode-range: + U+02C7, U+0301-0302, U+0304, U+0306-0307, U+0309, U+0323, U+0331, U+200C-200D, U+202E, U+25CC, + U+2D30-2D7F; +} +/* vietnamese */ +@font-face { + font-family: 'Google Sans Flex'; + font-style: normal; + font-weight: 700; + font-stretch: 100%; + font-display: swap; + src: url('/fonts/google-sans/33-t5s6IQcYNIWbFgDgAAzZ34auoVyXkJCOvp3SFWJbN5hF8Ju1x6sKCyp0l9sI40swNJwInycYAJzz0m7kJ4qFQOJBOjLvDSndo0SKMpKSTzwliVdHAy4xxhg2a2c.woff2') + format('woff2'); + unicode-range: + U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, + U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB; +} +/* latin-ext */ +@font-face { + font-family: 'Google Sans Flex'; + font-style: normal; + font-weight: 700; + font-stretch: 100%; + font-display: swap; + src: url('/fonts/google-sans/34-t5s6IQcYNIWbFgDgAAzZ34auoVyXkJCOvp3SFWJbN5hF8Ju1x6sKCyp0l9sI40swNJwInycYAJzz0m7kJ4qFQOJBOjLvDSndo0SKMpKSTzwliVdHAy4xxxg2a2c.woff2') + format('woff2'); + unicode-range: + U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, + U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, + U+A720-A7FF; +} +/* latin */ +@font-face { + font-family: 'Google Sans Flex'; + font-style: normal; + font-weight: 700; + font-stretch: 100%; + font-display: swap; + src: url('/fonts/google-sans/35-t5s6IQcYNIWbFgDgAAzZ34auoVyXkJCOvp3SFWJbN5hF8Ju1x6sKCyp0l9sI40swNJwInycYAJzz0m7kJ4qFQOJBOjLvDSndo0SKMpKSTzwliVdHAy4xyRg2.woff2') + format('woff2'); + unicode-range: + U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, + U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; +} diff --git a/frontend/src/app/tasks/tasks.css b/frontend/src/app/tasks/tasks.css index 31dfecf08..8c1bbe10e 100644 --- a/frontend/src/app/tasks/tasks.css +++ b/frontend/src/app/tasks/tasks.css @@ -33,3 +33,31 @@ .animate-slide { animation: slide-horizontal 1.5s ease-in-out infinite; } + +.wmde-markdown, +.markdown-content, +.enhanced-markdown, +.smart-text-line, +.chat-message-prompt { + font-family: + 'Google Sans Flex', + 'Google Sans', + -apple-system, + BlinkMacSystemFont, + 'Segoe UI', + Roboto, + 'Helvetica Neue', + Arial, + 'PingFang SC', + 'Hiragino Sans GB', + 'Microsoft YaHei', + sans-serif; + font-size: 16px; + font-weight: 400; + line-height: 28px; + letter-spacing: normal; +} + +.smart-text-line { + min-height: 28px; +} diff --git a/frontend/src/components/common/SmartUrlRenderer.tsx b/frontend/src/components/common/SmartUrlRenderer.tsx index c04618276..84247d08e 100644 --- a/frontend/src/components/common/SmartUrlRenderer.tsx +++ b/frontend/src/components/common/SmartUrlRenderer.tsx @@ -269,7 +269,11 @@ export function SmartTextLine({ }: SmartTextLineProps) { // If empty line, return non-breaking space to preserve line height if (!text) { - return
{'\u00A0'}
+ return ( +
+ {'\u00A0'} +
+ ) } // Detect URLs in the text @@ -277,7 +281,9 @@ export function SmartTextLine({ // If no URLs found, render as plain text if (detectedUrls.length === 0) { - return
{text}
+ return ( +
{text}
+ ) } // Build segments: alternating between plain text and URL components @@ -330,5 +336,9 @@ export function SmartTextLine({ } } - return
{segments}
+ return ( +
+ {segments} +
+ ) } diff --git a/frontend/src/features/settings/components/SkillListWithScope.tsx b/frontend/src/features/settings/components/SkillListWithScope.tsx index 19c659c72..b52743ab7 100644 --- a/frontend/src/features/settings/components/SkillListWithScope.tsx +++ b/frontend/src/features/settings/components/SkillListWithScope.tsx @@ -376,7 +376,9 @@ export function SkillListWithScope({ scope, selectedGroup }: SkillListWithScopeP {/* Go to Market button - only show if skill market is available and has URL */} {skillMarketInfo.available && skillMarketInfo.marketUrl && ( diff --git a/frontend/src/features/settings/components/skills/SkillSearchModal.tsx b/frontend/src/features/settings/components/skills/SkillSearchModal.tsx index 23437a904..6b01c6f86 100644 --- a/frontend/src/features/settings/components/skills/SkillSearchModal.tsx +++ b/frontend/src/features/settings/components/skills/SkillSearchModal.tsx @@ -226,11 +226,7 @@ export default function SkillSearchModal({ className="pl-9" /> - diff --git a/frontend/src/features/tasks/components/clarification/ClarificationQuestion.tsx b/frontend/src/features/tasks/components/clarification/ClarificationQuestion.tsx index e364a0572..66d5421da 100644 --- a/frontend/src/features/tasks/components/clarification/ClarificationQuestion.tsx +++ b/frontend/src/features/tasks/components/clarification/ClarificationQuestion.tsx @@ -107,7 +107,10 @@ export default function ClarificationQuestion({ } return ( -
+
{question.options?.map((option, index) => (
- {remainingContent &&
{remainingContent}
} + {remainingContent && ( +
{remainingContent}
+ )}
) } catch (e) { @@ -1282,7 +1284,9 @@ const MessageBubble = memo( const [prompt, result] = content.split('${$$}$') return ( <> - {prompt &&
{prompt}
} + {prompt && ( +
{prompt}
+ )} {result && renderMarkdownResult(result, prompt)} ) diff --git a/frontend/src/features/tasks/components/params/DeviceParamSync.tsx b/frontend/src/features/tasks/components/params/DeviceParamSync.tsx index d3fadd248..8f36ff88b 100644 --- a/frontend/src/features/tasks/components/params/DeviceParamSync.tsx +++ b/frontend/src/features/tasks/components/params/DeviceParamSync.tsx @@ -43,7 +43,7 @@ export default function DeviceParamSync() { // Wait for devices to load, then validate and select if (devices.length === 0) return - const deviceExists = devices.some((d) => d.device_id === deviceId) + const deviceExists = devices.some(d => d.device_id === deviceId) if (deviceExists) { setSelectedDeviceId(deviceId) syncedParamRef.current = deviceId diff --git a/frontend/src/features/tasks/components/selector/UnifiedRepositorySelector.tsx b/frontend/src/features/tasks/components/selector/UnifiedRepositorySelector.tsx index c742c1c26..b6e147d00 100644 --- a/frontend/src/features/tasks/components/selector/UnifiedRepositorySelector.tsx +++ b/frontend/src/features/tasks/components/selector/UnifiedRepositorySelector.tsx @@ -388,7 +388,11 @@ export default function UnifiedRepositorySelector({ const isLoading = repoLoading || branchLoading return ( -
+
{ diff --git a/frontend/src/features/tasks/components/sidebar/TaskInlineEdit.tsx b/frontend/src/features/tasks/components/sidebar/TaskInlineEdit.tsx index 20542c135..fbc2f597b 100644 --- a/frontend/src/features/tasks/components/sidebar/TaskInlineEdit.tsx +++ b/frontend/src/features/tasks/components/sidebar/TaskInlineEdit.tsx @@ -109,7 +109,7 @@ export default function TaskInlineEdit({ onClick={e => e.stopPropagation()} disabled={isSaving} className={cn( - 'w-full text-sm text-text-primary leading-tight px-1.5 py-0.5 rounded', + 'w-full text-sm font-medium text-[#444746] leading-5 px-1.5 py-0.5 rounded', 'border-2 outline-none transition-colors', 'bg-transparent', error ? 'border-red-500' : 'border-primary', diff --git a/frontend/src/features/tasks/components/sidebar/TaskListSection.tsx b/frontend/src/features/tasks/components/sidebar/TaskListSection.tsx index aefad3e29..3c352bc34 100644 --- a/frontend/src/features/tasks/components/sidebar/TaskListSection.tsx +++ b/frontend/src/features/tasks/components/sidebar/TaskListSection.tsx @@ -646,7 +646,7 @@ export default function TaskListSection({ }} /> ) : ( - + {localTitles[task.id] ?? task.title} )} diff --git a/frontend/src/features/tasks/components/sidebar/TaskSidebar.tsx b/frontend/src/features/tasks/components/sidebar/TaskSidebar.tsx index 46811bc83..2ff4e2ea5 100644 --- a/frontend/src/features/tasks/components/sidebar/TaskSidebar.tsx +++ b/frontend/src/features/tasks/components/sidebar/TaskSidebar.tsx @@ -312,7 +312,9 @@ export default function TaskSidebar({ > - {t('common:tasks.new_conversation')} + + {t('common:tasks.new_conversation')} + β€Ί @@ -340,7 +342,13 @@ export default function TaskSidebar({ - {btn.label} + + {btn.label} + {/* Show "New Task" button on hover when in code mode */} @@ -556,7 +564,7 @@ export default function TaskSidebar({ hideTitle={true} data-tour="task-sidebar" > - {sidebarContent} +
{sidebarContent}
{/* History Manage Dialog */} diff --git a/frontend/tailwind.config.js b/frontend/tailwind.config.js index de333da17..0142c4592 100644 --- a/frontend/tailwind.config.js +++ b/frontend/tailwind.config.js @@ -19,14 +19,17 @@ export default { extend: { fontFamily: { sans: [ - '"PingFang SC"', + '"Google Sans Flex"', + '"Google Sans"', '-apple-system', 'BlinkMacSystemFont', '"Segoe UI"', 'Roboto', '"Helvetica Neue"', 'Arial', - '"Noto Sans"', + '"PingFang SC"', + '"Hiragino Sans GB"', + '"Microsoft YaHei"', 'sans-serif', '"Apple Color Emoji"', '"Segoe UI Emoji"',