@goplusvn/core 0.1.72 → 0.1.74

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (33) hide show
  1. package/package.json +1 -1
  2. package/src/branding/__tests__/identity.test.ts +101 -0
  3. package/src/branding/__tests__/logo-route.test.ts +143 -0
  4. package/src/branding/identity.ts +74 -0
  5. package/src/branding/index.ts +36 -0
  6. package/src/branding/logo-route.ts +249 -0
  7. package/src/branding/pwa.tsx +146 -0
  8. package/src/branding/types.ts +45 -0
  9. package/src/providers/tenant-provider.tsx +10 -0
  10. package/src/styles/base.css +16 -0
  11. package/src/ui/auth/auth-layout.tsx +183 -21
  12. package/src/ui/errors/error-view.tsx +80 -87
  13. package/src/ui/errors/index.ts +6 -1
  14. package/src/ui/errors/not-found-view.tsx +89 -16
  15. package/src/ui/errors/status-page.tsx +132 -0
  16. package/src/ui/layout/logo.tsx +5 -0
  17. package/src/ui/pages/not-found.tsx +11 -27
  18. package/templates/starter-app/next.config.mjs +8 -0
  19. package/templates/starter-app/package.json +1 -0
  20. package/templates/starter-app/public/images/illustrations/characters/character-01.svg +33 -0
  21. package/templates/starter-app/public/images/illustrations/characters/character-02.svg +30 -0
  22. package/templates/starter-app/public/images/illustrations/characters/character-03.svg +30 -0
  23. package/templates/starter-app/public/images/illustrations/characters/character-04.svg +27 -0
  24. package/templates/starter-app/public/images/logos/goeat_logo.png +0 -0
  25. package/templates/starter-app/src/app/[lang]/(main)/admin/system/company/company-profile-form.tsx +21 -5
  26. package/templates/starter-app/src/app/[lang]/(plain)/sign-in/page.tsx +5 -4
  27. package/templates/starter-app/src/app/[lang]/layout.tsx +26 -1
  28. package/templates/starter-app/src/app/api/branding/logo/route.ts +25 -0
  29. package/templates/starter-app/src/app/layout.tsx +42 -1
  30. package/templates/starter-app/src/app/manifest.ts +23 -19
  31. package/templates/starter-app/src/configs/tenant.ts +6 -1
  32. package/templates/starter-app/src/providers/index.tsx +12 -2
  33. package/templates/starter-app/src/proxy.ts +3 -1
@@ -2,14 +2,10 @@
2
2
 
3
3
  import { useEffect, useState } from "react"
4
4
  import Link from "next/link"
5
- import {
6
- Button,
7
- Card,
8
- CardContent,
9
- CardHeader,
10
- CardTitle,
11
- } from "../index"
12
- import { AlertTriangle, Check, Copy, Home, RefreshCw } from "lucide-react"
5
+ import { Button } from "../index"
6
+ import { Check, Copy, Home, RefreshCw } from "lucide-react"
7
+
8
+ import { StatusPage, STATUS_ILLUSTRATION } from "./status-page"
13
9
 
14
10
 
15
11
  interface ErrorViewProps {
@@ -39,12 +35,19 @@ interface ErrorViewProps {
39
35
  * `error.message` bị Next thay bằng câu chung chung nên ghi thêm chỉ đẻ rác.
40
36
  * Vì vậy chỉ POST khi KHÔNG có digest — đó mới là lỗi runtime trình duyệt,
41
37
  * khoảng trống mà server không thấy.
38
+ *
39
+ * **Về hình thức**: dùng chung `StatusPage` với 404/403/400 — cùng bố cục của
40
+ * trang 404 trong bộ kit (hình minh hoạ + mã lỗi lớn + một câu + hàng nút).
41
+ * Trang lỗi là chỗ người dùng đang bực; hình vẽ nét mộc làm nó bớt lạnh, nhưng
42
+ * KHÔNG tô màu cảnh báo lòe loẹt và không có gì nhấp nháy: đây là lúc hỏng
43
+ * việc, không phải lúc đùa. Mã lỗi vẫn là chip mono chép được — phần duy nhất
44
+ * thật sự hữu ích ở màn này.
42
45
  */
43
46
  export function ErrorView({
44
47
  error,
45
48
  reset,
46
- title = "Đã xảy ra lỗi",
47
- description = "Hệ thống gặp sự cố khi hiển thị nội dung này. Đây là lỗi kỹ thuật tạm thời dữ liệu và quyền truy cập của bạn không thay đổi. Vui lòng thử lại; nếu vẫn lỗi, gửi mã lỗi bên dưới cho quản trị viên.",
49
+ title = "Trang gặp sự cố",
50
+ description = "Lỗi kỹ thuật tạm thời, dữ liệu của bạn không mất. Bạn thử lại một lần xem sao; nếu vẫn vậy, gửi mã lỗi bên dưới cho quản trị viên.",
48
51
  showHome = true,
49
52
  fullScreen = false,
50
53
  }: ErrorViewProps) {
@@ -78,87 +81,77 @@ export function ErrorView({
78
81
  }
79
82
  }
80
83
 
81
- const card = (
82
- <Card className="w-full max-w-lg">
83
- <CardHeader>
84
- <CardTitle className="flex items-center gap-2 text-destructive">
85
- <AlertTriangle className="h-5 w-5 shrink-0" />
86
- {title}
87
- </CardTitle>
88
- </CardHeader>
89
- <CardContent className="space-y-4">
90
- <p className="text-sm text-muted-foreground">{description}</p>
91
-
92
- {error.digest ? (
93
- <div className="flex items-center gap-2 rounded-md border border-border bg-muted/40 px-3 py-2">
94
- <span className="text-xs text-muted-foreground">Mã lỗi</span>
95
- <code className="flex-1 truncate font-mono text-xs text-foreground">
96
- {error.digest}
97
- </code>
98
- <Button
99
- variant="ghost"
100
- size="icon"
101
- className="h-7 w-7 shrink-0"
102
- onClick={handleCopy}
103
- title="Sao chép mã lỗi"
104
- >
105
- {copied ? (
106
- <Check className="h-3.5 w-3.5 text-emerald-600" />
107
- ) : (
108
- <Copy className="h-3.5 w-3.5" />
109
- )}
110
- </Button>
111
- </div>
112
- ) : null}
113
-
114
- {/* Chi tiết kỹ thuật chỉ mở ở máy dev. Trên production Next đã thay
115
- `message` bằng câu chung chung nên hiện ra cũng không giúp gì, mà
116
- còn dễ lộ đường dẫn nội bộ. */}
117
- {process.env.NODE_ENV === "development" && error.stack ? (
118
- <details className="rounded-md border border-border bg-muted/40 p-3">
119
- <summary className="cursor-pointer text-xs font-medium text-muted-foreground">
120
- Chi tiết kỹ thuật (chỉ hiện khi chạy dev)
121
- </summary>
122
- <pre className="mt-2 max-h-64 overflow-auto whitespace-pre-wrap break-all text-[11px] leading-relaxed text-muted-foreground">
123
- {error.stack}
124
- </pre>
125
- </details>
126
- ) : null}
127
-
128
- <div className="flex flex-wrap gap-2">
129
- {reset ? (
130
- <Button onClick={reset}>
131
- <RefreshCw className="mr-2 h-4 w-4" />
132
- Thử lại
133
- </Button>
134
- ) : null}
135
- <Button variant="outline" onClick={() => window.location.reload()}>
136
- Tải lại trang
84
+ const details = (
85
+ <>
86
+ {error.digest ? (
87
+ <div className="flex items-center gap-2 rounded-md border border-border bg-muted/40 py-1 pl-2.5 pr-1">
88
+ <span className="shrink-0 text-[11px] uppercase tracking-wide text-muted-foreground">
89
+ Mã lỗi
90
+ </span>
91
+ <code className="min-w-0 flex-1 truncate font-mono text-xs text-foreground">
92
+ {error.digest}
93
+ </code>
94
+ <Button
95
+ variant="ghost"
96
+ size="icon-xs"
97
+ className="shrink-0 text-muted-foreground"
98
+ onClick={handleCopy}
99
+ title="Sao chép mã lỗi"
100
+ >
101
+ {copied ? (
102
+ <Check className="h-3.5 w-3.5 text-emerald-600" />
103
+ ) : (
104
+ <Copy className="h-3.5 w-3.5" />
105
+ )}
137
106
  </Button>
138
- {showHome ? (
139
- <Button variant="ghost" asChild>
140
- <Link href="/">
141
- <Home className="mr-2 h-4 w-4" />
142
- Về trang chủ
143
- </Link>
144
- </Button>
145
- ) : null}
146
107
  </div>
147
- </CardContent>
148
- </Card>
149
- )
108
+ ) : null}
150
109
 
151
- if (!fullScreen) {
152
- return (
153
- <div className="flex min-h-0 flex-1 items-center justify-center p-4">
154
- {card}
155
- </div>
156
- )
157
- }
110
+ {/* Chi tiết kỹ thuật chỉ mở ở máy dev. Trên production Next đã thay
111
+ `message` bằng câu chung chung nên hiện ra cũng không giúp gì, mà
112
+ còn dễ lộ đường dẫn nội bộ. */}
113
+ {process.env.NODE_ENV === "development" && error.stack ? (
114
+ <details className="group rounded-md border border-border bg-muted/40 px-2.5 py-1.5">
115
+ <summary className="cursor-pointer list-none text-[11px] font-medium text-muted-foreground select-none hover:text-foreground">
116
+ <span className="mr-1 inline-block transition-transform group-open:rotate-90">
117
+
118
+ </span>
119
+ Chi tiết kỹ thuật (chỉ hiện khi chạy dev)
120
+ </summary>
121
+ <pre className="mt-2 max-h-56 overflow-auto whitespace-pre-wrap break-all font-mono text-[11px] leading-relaxed text-muted-foreground">
122
+ {error.stack}
123
+ </pre>
124
+ </details>
125
+ ) : null}
126
+ </>
127
+ )
158
128
 
159
129
  return (
160
- <div className="flex min-h-screen items-center justify-center bg-background p-4">
161
- {card}
162
- </div>
130
+ <StatusPage
131
+ code="500"
132
+ title={title}
133
+ description={description}
134
+ illustration={STATUS_ILLUSTRATION.error}
135
+ fullScreen={fullScreen}
136
+ extra={error.digest || process.env.NODE_ENV === "development" ? details : null}
137
+ >
138
+ {reset ? (
139
+ <Button onClick={reset}>
140
+ <RefreshCw className="mr-1.5 h-4 w-4" />
141
+ Thử lại
142
+ </Button>
143
+ ) : null}
144
+ <Button variant="outline" onClick={() => window.location.reload()}>
145
+ Tải lại trang
146
+ </Button>
147
+ {showHome ? (
148
+ <Button variant="ghost" className="text-muted-foreground" asChild>
149
+ <Link href="/">
150
+ <Home className="mr-1.5 h-4 w-4" />
151
+ Về trang chủ
152
+ </Link>
153
+ </Button>
154
+ ) : null}
155
+ </StatusPage>
163
156
  )
164
157
  }
@@ -1,2 +1,7 @@
1
- export { NotFoundView } from "./not-found-view";
1
+ export { StatusPage, STATUS_ILLUSTRATION } from "./status-page";
2
+ export {
3
+ NotFoundView,
4
+ ForbiddenView,
5
+ BadRequestView,
6
+ } from "./not-found-view";
2
7
  export { ErrorView } from "./error-view";
@@ -1,14 +1,13 @@
1
1
  "use client"
2
2
  import Link from "next/link"
3
3
  import { Button } from "../index"
4
- import { FileQuestion } from "lucide-react"
5
4
 
6
- import { cn } from "../../utils"
5
+ import { StatusPage, STATUS_ILLUSTRATION } from "./status-page"
7
6
 
8
7
  /**
9
- * Màn "không tìm thấy" cho `not-found.tsx`. Tách khỏi `NotFoundPage` của core
10
- * bản core là tiếng Anh, `min-h-screen` (tràn khi nằm trong vỏ app có sidebar)
11
- * phụ thuộc một file SVG minh hoạ.
8
+ * Màn "không tìm thấy" cho `not-found.tsx`. Tách khỏi `NotFoundPage` của kit
9
+ * bản kit là tiếng Anh `min-h-screen` cứng (tràn khi nằm trong vỏ app có
10
+ * sidebar) còn bố cục thì dùng lại nguyên qua `StatusPage`.
12
11
  *
13
12
  * Đây là màn cho `notFound()` gọi TỪ TRONG trang — chứng từ bị xoá, id sai, hết
14
13
  * quyền xem. Khác với URL gõ sai: cái đó do `[lang]/[...not-found]/page.tsx` lo.
@@ -25,20 +24,94 @@ export function NotFoundView({
25
24
  fullScreen?: boolean
26
25
  }) {
27
26
  return (
28
- <div
29
- className={cn(
30
- "flex flex-col items-center justify-center gap-4 p-8 text-center",
31
- fullScreen ? "min-h-screen bg-background" : "min-h-0 flex-1"
32
- )}
27
+ <StatusPage
28
+ code="404"
29
+ title={title}
30
+ description={description}
31
+ illustration={STATUS_ILLUSTRATION.notFound}
32
+ fullScreen={fullScreen}
33
33
  >
34
- <FileQuestion className="h-12 w-12 text-muted-foreground" />
35
- <div className="space-y-1">
36
- <h1 className="text-xl font-bold">{title}</h1>
37
- <p className="max-w-md text-sm text-muted-foreground">{description}</p>
38
- </div>
39
34
  <Button asChild>
40
35
  <Link href={homeHref}>Về trang chủ</Link>
41
36
  </Button>
42
- </div>
37
+ </StatusPage>
38
+ )
39
+ }
40
+
41
+ /**
42
+ * Màn "không có quyền". Trước đây app không có màn này: `requirePageAccess`
43
+ * lặng lẽ đẩy người dùng về trang chủ, nên người bị thiếu quyền chỉ thấy mình
44
+ * "bị bật ra" mà không biết vì sao và phải xin ai.
45
+ */
46
+ export function ForbiddenView({
47
+ title = "Bạn không có quyền vào trang này",
48
+ description = "Tài khoản của bạn chưa được cấp quyền cho chức năng này. Nếu cần dùng, hãy báo quản trị viên kèm tên quyền bên dưới.",
49
+ permission,
50
+ homeHref = "/",
51
+ fullScreen = false,
52
+ }: {
53
+ title?: string
54
+ description?: string
55
+ /** Mã quyền còn thiếu, dạng `resource:action` — thứ quản trị viên cần để tick. */
56
+ permission?: string
57
+ homeHref?: string
58
+ fullScreen?: boolean
59
+ }) {
60
+ return (
61
+ <StatusPage
62
+ code="403"
63
+ title={title}
64
+ description={description}
65
+ illustration={STATUS_ILLUSTRATION.forbidden}
66
+ fullScreen={fullScreen}
67
+ extra={
68
+ permission ? (
69
+ <div className="flex items-center gap-2 rounded-md border border-border bg-muted/40 px-2.5 py-1.5">
70
+ <span className="shrink-0 text-[11px] uppercase tracking-wide text-muted-foreground">
71
+ Quyền cần cấp
72
+ </span>
73
+ <code className="min-w-0 flex-1 truncate font-mono text-xs text-foreground">
74
+ {permission}
75
+ </code>
76
+ </div>
77
+ ) : null
78
+ }
79
+ >
80
+ <Button asChild>
81
+ <Link href={homeHref}>Về trang chủ</Link>
82
+ </Button>
83
+ </StatusPage>
84
+ )
85
+ }
86
+
87
+ /**
88
+ * Màn "yêu cầu không hợp lệ" (400): tham số trên URL sai kiểu, thiếu mã, ngày
89
+ * không đọc được. Khác 404 ở chỗ đường dẫn có tồn tại — chỉ dữ liệu gửi kèm là
90
+ * sai, nên lối thoát là quay lại chứ không phải về trang chủ.
91
+ */
92
+ export function BadRequestView({
93
+ title = "Yêu cầu không hợp lệ",
94
+ description = "Đường dẫn hoặc bộ lọc kèm theo không đúng định dạng nên trang không mở được. Hãy quay lại và thao tác từ danh sách.",
95
+ homeHref = "/",
96
+ fullScreen = false,
97
+ }: {
98
+ title?: string
99
+ description?: string
100
+ homeHref?: string
101
+ fullScreen?: boolean
102
+ }) {
103
+ return (
104
+ <StatusPage
105
+ code="400"
106
+ title={title}
107
+ description={description}
108
+ illustration={STATUS_ILLUSTRATION.invalid}
109
+ fullScreen={fullScreen}
110
+ >
111
+ <Button onClick={() => window.history.back()}>Quay lại</Button>
112
+ <Button variant="outline" asChild>
113
+ <Link href={homeHref}>Về trang chủ</Link>
114
+ </Button>
115
+ </StatusPage>
43
116
  )
44
117
  }
@@ -0,0 +1,132 @@
1
+ "use client"
2
+
3
+ import { useState } from "react"
4
+
5
+ import { cn } from "../../utils"
6
+
7
+ /**
8
+ * Khung chung cho MỌI màn trạng thái: 404, 403, 400, lỗi hệ thống.
9
+ *
10
+ * Bố cục là của trang 404 sẵn có trong bộ kit (`ui/pages/not-found.tsx`): hình
11
+ * minh hoạ nằm cạnh mã lỗi cỡ lớn, tiêu đề lồng dưới mã, rồi một câu giải
12
+ * thích và hàng nút. Không vẽ mới — việc ở đây là gom thành một khung dùng
13
+ * chung, dịch sang tiếng Việt, và sửa ba chỗ khiến bản kit không dùng được
14
+ * trong app thật:
15
+ *
16
+ * 1. `min-h-screen` cứng ⇒ tràn khi màn nằm trong vỏ app có sidebar. Nay chọn
17
+ * theo `fullScreen`, và cỡ chữ/hình co lại khi nhúng — trang chiếm cả màn
18
+ * thì nói to được, còn thay mỗi vùng nội dung mà vẫn hét cỡ 60px thì lạc
19
+ * quẻ với phần còn lại của app.
20
+ * 2. Hình kit là nét đen trên nền trong suốt ⇒ **tàng hình ở dark mode**. Nay
21
+ * `dark:invert`.
22
+ * 3. App nào chưa chép `public/images/illustrations` sẽ hiện ô ảnh vỡ. Nay
23
+ * `onError` ⇒ bỏ hình, phần chữ vẫn đủ nghĩa.
24
+ */
25
+ export function StatusPage({
26
+ code,
27
+ title,
28
+ description,
29
+ illustration,
30
+ fullScreen = false,
31
+ children,
32
+ extra,
33
+ }: {
34
+ /** Mã trạng thái, hiện cỡ lớn. Bỏ trống khi không có mã (lỗi phía client). */
35
+ code?: string
36
+ title: string
37
+ description?: string
38
+ /** Đường dẫn hình trong `public/` của app. Thiếu file thì tự bỏ hình. */
39
+ illustration?: string
40
+ fullScreen?: boolean
41
+ /** Hàng nút hành động. */
42
+ children?: React.ReactNode
43
+ /** Khối phụ giữa mô tả và nút — mã lỗi, chi tiết kỹ thuật… */
44
+ extra?: React.ReactNode
45
+ }) {
46
+ const [imageBroken, setImageBroken] = useState(false)
47
+
48
+ return (
49
+ <div
50
+ className={cn(
51
+ // `w-full` bắt buộc: boundary tầng [lang] thay cả vỏ app nhưng vẫn nằm
52
+ // trong SidebarProvider (`display:flex`) — thiếu nó thì khối co lại
53
+ // bằng nội dung và dán vào mép trái dù đã `justify-center`.
54
+ "flex w-full flex-col items-center justify-center gap-6 p-6 text-center",
55
+ fullScreen ? "min-h-screen bg-background" : "min-h-0 flex-1"
56
+ )}
57
+ >
58
+ <div
59
+ className={cn(
60
+ "motion-safe:animate-status-in flex flex-col-reverse items-center justify-center gap-4",
61
+ "sm:flex-row sm:gap-6 sm:text-start"
62
+ )}
63
+ >
64
+ {illustration && !imageBroken ? (
65
+ // <img> chứ không phải next/image: cần `onError` để app thiếu file
66
+ // ảnh vẫn ra màn tử tế, và không phải khai `images` trong next.config.
67
+ // eslint-disable-next-line @next/next/no-img-element
68
+ <img
69
+ src={illustration}
70
+ alt=""
71
+ aria-hidden
72
+ onError={() => setImageBroken(true)}
73
+ className={cn(
74
+ "w-auto select-none dark:invert",
75
+ fullScreen ? "h-40 sm:h-48" : "h-28 sm:h-36"
76
+ )}
77
+ />
78
+ ) : null}
79
+
80
+ <h1
81
+ className={cn(
82
+ "inline-grid font-black leading-none tracking-tight text-foreground",
83
+ fullScreen ? "text-5xl sm:text-6xl" : "text-4xl"
84
+ )}
85
+ >
86
+ {code}
87
+ <span
88
+ className={cn(
89
+ "font-semibold text-balance leading-snug",
90
+ code ? "mt-2" : null,
91
+ fullScreen ? "text-2xl sm:text-3xl" : "text-lg"
92
+ )}
93
+ >
94
+ {title}
95
+ </span>
96
+ </h1>
97
+ </div>
98
+
99
+ {description ? (
100
+ <p
101
+ className={cn(
102
+ "motion-safe:animate-status-in max-w-prose text-pretty leading-relaxed text-muted-foreground [animation-delay:60ms]",
103
+ fullScreen ? "text-base" : "text-sm"
104
+ )}
105
+ >
106
+ {description}
107
+ </p>
108
+ ) : null}
109
+
110
+ {extra ? (
111
+ <div className="motion-safe:animate-status-in w-full max-w-md space-y-2 text-left [animation-delay:100ms]">
112
+ {extra}
113
+ </div>
114
+ ) : null}
115
+
116
+ {children ? (
117
+ <div className="motion-safe:animate-status-in flex flex-wrap items-center justify-center gap-2 [animation-delay:140ms]">
118
+ {children}
119
+ </div>
120
+ ) : null}
121
+ </div>
122
+ )
123
+ }
124
+
125
+ /** Hình của bộ kit, dùng lại nguyên — app chép sẵn trong `public/`. */
126
+ export const STATUS_ILLUSTRATION = {
127
+ /** Bản kit vốn dùng hình này cho 404. Giữ nguyên để không đổi cái đã quen. */
128
+ notFound: "/images/illustrations/characters/character-02.svg",
129
+ forbidden: "/images/illustrations/characters/character-01.svg",
130
+ invalid: "/images/illustrations/characters/character-03.svg",
131
+ error: "/images/illustrations/characters/character-04.svg",
132
+ } as const
@@ -14,6 +14,11 @@ const DEFAULT_TAGLINE = "ERP System";
14
14
  * KHÔNG có logo cấu hình → monogram chữ cái đầu, KHÔNG trỏ vào một file magic
15
15
  * trong public/. Bản cũ default "/images/logos/goeat_logo.png" (di sản goeat)
16
16
  * làm mọi app mới init 400 ảnh trên từng trang vì template không ship file đó.
17
+ *
18
+ * Logo mặc định của app init GIỜ nằm ở tầng app, đúng chỗ có thể ship kèm file:
19
+ * templates/starter-app/public/images/logos/goeat_logo.png +
20
+ * `tenant.branding.logo` trong src/configs/tenant.ts (bị `Company.logoUrl` đè
21
+ * khi admin upload). Đừng hardcode lại đường dẫn nào vào component này.
17
22
  */
18
23
  function Monogram({
19
24
  name,
@@ -1,30 +1,14 @@
1
- import Image from "next/image";
2
- import Link from "next/link";
3
- import { Button } from "../primitives/button";
1
+ import { NotFoundView } from "../errors/not-found-view";
4
2
 
3
+ /**
4
+ * Trang 404 cho URL gõ sai (`[lang]/[...not-found]/page.tsx` của app bọc nó
5
+ * trong vỏ app có sidebar).
6
+ *
7
+ * Bố cục gốc của bộ kit nay sống trong `NotFoundView`/`StatusPage`, nên đây chỉ
8
+ * còn là lối vào giữ nguyên tên cho app đang import. Hai thứ sửa cùng lúc:
9
+ * chữ tiếng Việt như phần còn lại của app, và bỏ `min-h-screen` — nó nằm TRONG
10
+ * vỏ app nên chiều cao cứng làm trang thừa ra một màn cuộn.
11
+ */
5
12
  export function NotFoundPage() {
6
- return (
7
- <div className="min-h-screen w-full flex flex-col items-center justify-center gap-y-6 text-center text-foreground bg-background p-4">
8
- <div className="flex flex-col-reverse justify-center items-center gap-y-6 md:flex-row md:text-start">
9
- <Image
10
- src="/images/illustrations/characters/character-02.svg"
11
- alt=""
12
- height={232}
13
- width={249}
14
- priority
15
- />
16
-
17
- <h1 className="inline-grid text-6xl font-black">
18
- 404 <span className="text-3xl font-semibold">Page Not Found</span>
19
- </h1>
20
- </div>
21
- <p className="max-w-prose text-xl text-muted-foreground">
22
- We couldn&apos;t find the page you&apos;re looking for. It might have
23
- been moved or doesn&apos;t exist.
24
- </p>
25
- <Button size="lg" asChild>
26
- <Link href="/">Home Page</Link>
27
- </Button>
28
- </div>
29
- );
13
+ return <NotFoundView />;
30
14
  }
@@ -35,6 +35,14 @@ const nextConfig = {
35
35
  // "@goerp/core" (giữ qua alias pnpm) còn package thật trên đĩa là "@goplusvn/core".
36
36
  transpilePackages: ["@goerp/core", "@goplusvn/core"],
37
37
 
38
+ // Next 16 CHẶN next/image tối ưu ảnh local có query string nếu path đó chưa
39
+ // khai (chống enumeration). Logo phục vụ qua `/api/branding/logo?v=<updatedAt>`
40
+ // nên không khai là sidebar ném lỗi đỏ ngay khi vào app. Bỏ trống `search`
41
+ // = cho phép MỌI query trên đúng path đó.
42
+ images: {
43
+ localPatterns: [{ pathname: "/api/branding/logo" }],
44
+ },
45
+
38
46
  // Docker image gọn: chỉ .next/standalone + static. Xem Dockerfile.
39
47
  output: "standalone",
40
48
  turbopack: { root: workspaceRoot },
@@ -38,6 +38,7 @@
38
38
  "react-dom": "19.2.0",
39
39
  "react-hook-form": "^7.54.2",
40
40
  "server-only": "^0.0.1",
41
+ "sharp": "^0.34.5",
41
42
  "sonner": "2.0.2",
42
43
  "swr": "^2.3.6",
43
44
  "zod": "3.23.8"
@@ -0,0 +1,33 @@
1
+ <svg version="1.2" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 171 242" width="171" height="242">
2
+ <title>character-01</title>
3
+ <style>
4
+ .s0 { fill: #ffffff }
5
+ .s1 { fill: #000000 }
6
+ </style>
7
+ <g id="Introduction">
8
+ <g id="variations">
9
+ <g id="images">
10
+ <g id="a-person/bust">
11
+ <g id="body/Button-Shirt-1">
12
+ <path id="🎨-Background" fill-rule="evenodd" class="s0" d="m13.5 237.1c27.6 4.1 55.7 4.4 83.5 2.8 11-0.8 22.1-0.9 33.1 0.1 6.5 0.5 35 2.7 37.3-3.1-1.5-31.1-4.4-62.4-13.5-92.2-3.8-10.6-7-19.4-14.3-28.2-2.3-2.4-7.3-7.4-10.1-9-2.5-1.4-3.5-0.9-4.9-3.3-1.5-2.7-2.5-7.1-4.5-9-2-1.9-5-1.2-8.8-0.6 0.7-9.3-3.6-11.6-9.5-13.4-10.4-3.9-20.6-2-23.2 10.7-4.9 0-7.6 2.1-10.5 4.1-1.2 0.8-0.4 2.9-1.8 3.5-2.7 1-7.4 0.7-9.9 1.9-11.7 5.3-22 13-28.8 24.2-15.3 23.9-25.7 74.3-23.9 102.7-0.8 1.3 0.3 3 0.6 4.4 0.3 1.2 1.5 1.9 2.6 1.8 1.7 1.8 4.3 2.2 6.6 2.6z"/>
13
+ <path id="🖍-Ink" fill-rule="evenodd" class="s1" d="m127.7 106.8c-0.2-0.1 0-0.4 0.2-0.3 8.1 3.9 14.4 10.6 18.8 18.4 4.6 8.1 7.2 17.2 9.5 26.2l0.1 0.3c2.4 9.6 4.4 19.2 6.2 28.9 1.9 9.8 3.4 19.7 4.6 29.6q0.9 7.4 1.5 14.8 0.3 3.7 0.6 7.4 0.1 1.4 0.2 2.9v0.8c0 0.6 0.1 1.3-0.1 2-0.1 0.5-0.4 1-0.7 1.6-0.5 1-1.9 0.8-2.5 0l-0.2-0.3c-0.3-0.6-0.6-1.1-0.8-1.8-0.1-0.7-0.1-1.5-0.1-2.2q-0.2-1.9-0.3-3.9-0.3-4.1-0.6-8.2c-0.5-5.4-1-10.8-1.6-16.1q-1.7-14.4-4.2-28.6c-1.6-9.3-3.6-18.5-5.7-27.6l-0.2-1c-3.7-16-9.4-34.4-24.7-42.9zm-87.2 62.6c0.1-0.2 0.3-0.2 0.4 0 0.5 2.5 0.6 5 0.7 7.6q0.1 3.8 0 7.5c-0.1 9.3-0.4 18.5-0.6 27.7q-0.2 6.9-0.3 13.8 0 2.6-0.1 5.2v2.3c0 1 0 2-0.1 3-0.1 0.7-0.3 1.3-0.7 1.9-0.2 0.4-0.6 0.6-1 0.9q-0.7 0.6-1.4 0l-0.2-0.1c-0.4-0.3-0.8-0.6-1-1.1-0.4-0.8-0.5-1.6-0.6-2.4-0.1-1.3 0-2.5 0-3.8q0.1-3.8 0.1-7.5c0.2-9.3 0.5-18.5 1.1-27.7q0.4-6.5 1.1-13l0.1-0.8q0.3-2 0.5-3.9c-2.3-1.6-4.4-3.6-6.1-5.9-0.2-0.2 0-0.4 0.2-0.2 1.8 1.8 3.8 3.3 6.1 4.4 0.4-2.7 0.9-5.4 1.8-7.9zm38.9-82.3q0.1 0 0.1 0c0.5 0.6 0.4 1.5 0.4 2.2v0.1q0.1 1.6 0.1 3.3v3.4c0 0.5-0.1 1-0.1 1.4l0.1 0.2c0.2 0.3 0.3 0.7 0.3 1.1-0.1 0.5-0.3 0.9-0.7 1.2l0.8 1.1 0.8 1.2q2.6 3.6 5.2 7.1 2.7 3.6 5.8 6.9 1.5 1.6 3 3.1 0.7 0.7 1.3 1.3l0.4 0.4c0.3 0.2 0.6 0.5 0.7 0.8 0.1 0.2 0.2 0.6 0.2 0.7 0.3 0.7-0.2 1.8-1.1 1.5v-0.1q0.3-0.1-0.3 0-0.3 0-0.6-0.1l-0.1-0.1c-0.3-0.1-0.5-0.4-0.8-0.6v-0.1q-0.8-0.7-1.6-1.5-1.6-1.6-3.1-3.4-3-3.4-5.7-7.1c-1.9-2.4-3.6-5.1-5-7.8q-0.9-1.5-1.6-3.1c-0.9-0.3-1.2-1.4-1.1-2.5-0.4-0.8-0.7-1.7-0.9-2.5 0-0.1 0.2-0.2 0.3-0.1q0.4 0.5 0.8 1.1c0.2-0.8 0.4-1.6 0.5-2.1l0.4-2c-2.4-0.2-5 0.8-6.6 2.5-0.1 0.5-0.5 0.8-0.8 1.2q-0.6 0.7-1 1.6c-0.5 1.2-0.2 3.1-1.3 4q-0.2 0.1-0.3 0.2c0.5 2.5 0.2 5.2 0.2 7.8v0.2c0 2.8-0.1 5.6-0.2 8.5l-0.1 2.8c-0.1 3.7-0.2 7.5 0.1 11.2q2.5-2.2 5.2-4.2 1.7-1.3 3.5-2.6l1-0.6c1.2-0.8 2.4-1.6 3.7-2.2 1.7-0.7 3.3-0.5 4.9 0.3 1.6 0.7 3.2 1.6 4.8 2.4q2.4 1.3 4.9 2.5c1.1 0.6 2.6 1.1 3.4 2.1q0.1-0.4 0.2-0.7c-0.1-0.3-0.1-0.7 0.1-1 2.7-4.9 5.1-9.9 7.6-14.9 1.2-2.5 2.4-5 3.6-7.6l1.2-2.4q0.3-0.6 0.6-1.2 0.5-0.9 0.9-1.9c0.2-0.2 0.3-0.5 0.4-0.7l0.1-0.2c0 0 0.3-0.9 0.1-0.8h-0.1c-0.1 0.1-0.2-0.1-0.1-0.2 0.3-0.3 0.8 0 1 0.4 0.5 1-0.5 2.5-0.8 3.5-1.1 3.1-2.4 6.2-3.6 9.2-2.4 5.8-5.1 11.5-7.7 17.2v0.1c0.6-0.4 1.2-0.8 1.7-1.2q1.9-1.4 3.9-2.7 3.6-2.5 7.4-4.7l0.5-0.3c1.2-0.7 2.5-1.3 4-1.1 1.4 0.2 2.7 0.9 3.9 1.5l0.1 0.1 3.9 1.9q-0.6-2.5-1.3-5-1.4-4.8-3-9.5-1.5-4.4-3.3-8.7l-0.3-0.8c-0.5-1.2-1-2.5-2.3-2.9-1.4-0.4-3 0.2-4.2-0.6-0.1-0.1-0.1-0.2 0.1-0.3l0.7-0.2c1.4-0.3 3.1-0.7 4.5-0.3 1.5 0.3 2.7 1.6 3.4 2.9 0.8 1.4 1.3 3 2 4.5v0.3q1.1 2.6 2 5.2 2 5.2 3.5 10.6 0.8 2.6 1.5 5.2c0.1 0.5 0.3 1.1 0.5 1.7q0.3 0.3 0.6 0.7c0.3 0.4 0.1 0.9-0.3 1.2q0 0.6-0.3 1.1c-0.9 1.4-3.3 1.1-3.2-0.8q0-0.4 0.3-0.7v-0.1l-0.1-0.1q-0.6-0.3-1.2-0.6l-4.1-2c-1.2-0.6-2.5-1.5-3.8-1.7-1.2-0.2-2.5 0.7-3.5 1.3h-0.1q-3.8 1.9-7.5 4-1.9 1-3.7 2c-1 0.6-2.1 1.4-3.3 1.7-0.4 0.4-1 0.3-1.5 0 0.2 1.3 0.2 2.7 0.3 4.1 0.1 1.8 0.1 3.6 0.1 5.4v0.7q0.1 6 0.1 12c0.1 14.2-0.1 28.5-0.1 42.7 0 7.2-0.2 14.3-0.3 21.5-0.1 3-0.3 6-0.5 9.1l-0.1 1.6c-0.2 3.5-0.3 7-0.9 10.5-0.1 0.4-0.9 0.4-1 0-0.5-3.7-0.6-7.5-0.7-11.2v-0.8q-0.2-6-0.2-12c0-14.2 0.4-28.5 0.7-42.7 0.2-7.2 0.3-14.3 0.5-21.5q0.2-5.3 0.4-10.7 0.1-2.4 0.3-4.8v-0.7q0.1-0.7 0.1-1.3c-1.4 0.5-2.8-0.5-4.1-1.1q-2.2-1.2-4.4-2.3l-1.5-0.8-3-1.5c-1.4-0.7-2.4-1.4-3.9-0.6-5.1 2.9-9.9 6.8-14.2 10.8-0.8 0.8-2.6 0.6-2.8-0.7-0.9-5.6-0.3-11.2 0.1-16.8l0.2-2.1q0.3-3.7 0.7-7.4 0.2-1.7 0.4-3.3l0.1-0.9c0.2-1.3 0.3-2.6 0.7-3.8q-0.2-0.1-0.3-0.2c-1.2-1.1-0.6-3.1-0.1-4.4 0.5-1.3 1.3-2.4 2.3-3.4 0.3-0.2 0.6-0.4 0.9-0.4 2.4-1.6 5.1-2.4 7.9-1.5q0.1-0.6 0.2-1.1l0.1-0.4c0.2-0.9 0.3-2.4 1.1-3.1zm25 146.1c0.8-0.2 1.6 0 2.2 0.6 0.5 0.5 0.7 1.4 0.5 2.1q-0.1 0.6-0.5 1-0.4 0.4-0.9 0.5l-0.1 0.1h-0.1q-0.6 0.2-1.2 0-0.5-0.1-0.9-0.5-0.4-0.4-0.6-1-0.1-0.5 0-1.1l0.1-0.1q0.1-0.6 0.6-1 0.4-0.4 0.9-0.6zm45-75.5c0.1-0.1 0.3 0.1 0.2 0.2-1.1 2.3-2.5 4.6-3.7 6.9q0.1 0.9 0.3 1.8c0.5 2.6 1.1 5.1 1.5 7.7 1.4 9.4 2.2 18.8 2.8 28.3 0.7 9.4 0.8 18.9 0.9 28.4 0 0.8-0.7 1.7-1.5 1.9-0.4 0.1-0.7 0.1-1.1 0-0.8-0.1-1.4-1.1-1.4-1.9q-0.4-8-1-15.9c-0.7-9.4-1.1-18.8-1.7-28.2l-0.2-3.3c-0.2-3.5-0.4-7.1-0.5-10.7 0-2.3 0.1-4.7 0-7 0-2.2-0.3-4.6 0.2-6.7 0-0.1 0.2-0.1 0.2 0 0.5 1 0.8 2.2 1 3.3 1.3-1.6 2.6-3.2 4-4.8zm-84.2-57.5c0.2 0 0.2 0.3 0 0.3-2.5 0.3-4.9 1.3-7.3 2.2l-0.2 0.1q-3.6 1.3-7 3.1c-4.4 2.4-8.5 5.4-12.1 8.9-14.3 13.9-20.8 34-25.6 52.9-2.6 10.5-4.5 21.2-5.7 32q-0.9 8-1.3 16-0.2 4.1-0.3 8.2 0 2.1 0 4.2c0 0.7 0.1 1.5 0 2.1-0.2 0.6-0.6 1.1-1 1.6-0.4 0.6-1.1 0.5-1.5 0l-0.1-0.2c-0.5-0.6-0.9-1.1-0.9-1.9-0.1-0.8-0.1-1.6-0.1-2.4q0-2.4 0.1-4.8 0.1-4.6 0.3-9.2 0.6-9.4 1.9-18.7c1.5-11 3.8-21.9 6.8-32.6 2.9-10.1 6.2-20.1 11-29.4 4.5-8.7 10.3-16.8 18-22.9 3.6-2.8 7.5-5.1 11.7-6.9 2.1-0.9 4.3-1.6 6.6-2 2.2-0.4 4.5-0.4 6.7-0.6zm39.7 115.2c0.4 0 0.8 0.1 1.1 0.3l0.5 0.4q0.2 0.2 0.4 0.4c0.3 0.4 0.3 1 0.2 1.5q0 0.4-0.2 0.8l-0.4 0.4c-0.3 0.3-0.6 0.5-1 0.6q-0.3 0.1-0.6 0.1h-0.1 0.1-0.1q-0.1 0-0.2 0-0.1 0-0.2 0 0 0-0.1 0c-0.5 0-1-0.3-1.4-0.6-0.3-0.3-0.6-1-0.6-1.4l0.1-0.2c0-0.3 0-0.5 0.2-0.8q0.1-0.4 0.5-0.8 0.8-0.7 1.8-0.7zm-1.6-23.5c0.6-0.8 1.8-0.8 2.7-0.4 0.2 0.1 0.4 0.3 0.5 0.5 0.5 0.3 0.7 1 0.7 1.6 0 0.5-0.3 1.2-0.7 1.6v0.1c-0.3 0.2-0.6 0.4-1 0.5-0.5 0.1-0.9 0.1-1.4-0.2q-0.7-0.2-1.1-0.8v-0.1q0 0-0.1-0.1c-0.5-0.9-0.3-2 0.4-2.7zm0.3-23.7q0.5-0.1 0.9 0 0.4 0 0.6 0.1 0.3 0.1 0.5 0.3 0.3 0.2 0.5 0.5 0.3 0.3 0.4 0.8l0.1 0.6-0.1 0.6-0.3 0.5q-0.1 0.2-0.2 0.3-0.1 0.3-0.4 0.4-0.1 0.2-0.4 0.3c-0.5 0.3-1.2 0.5-1.8 0.3q-0.5-0.2-0.9-0.6-0.4-0.4-0.6-0.9v-0.3c-0.1-0.4-0.1-0.6 0-1.1 0.1-0.2 0.2-0.5 0.3-0.7 0.3-0.5 0.8-0.9 1.4-1.1zm26.9-17q1.3 0 2.6 0h0.7c1.1 0.1 2-0.1 2.9 0.7 0.7 0.6 0.4 1.5-0.2 1.9-0.9 0.7-2.1 0.4-3.1 0.3q-1.7-0.1-3.4-0.2-3.2-0.1-6.4-0.2-3.2 0-6.5 0.1c-2.1 0-4.4 0.2-6.6 0-0.3 0-0.4-0.4-0.1-0.5 2.1-0.7 4.4-1 6.5-1.2q3.3-0.5 6.7-0.6 3.4-0.2 6.9-0.3zm-26.9-6.9h0.1q0.6 0 1.1 0.2l0.1 0.1 0.4 0.3q0.5 0.5 0.6 1.1l0.1 0.6q0 0.5-0.2 0.9-0.1 0.4-0.5 0.7-0.3 0.4-0.7 0.5-0.4 0.2-0.8 0.2h-0.1q-0.6 0-1.2-0.3l-0.5-0.4q-0.4-0.4-0.6-1v-0.6q-0.1-0.5 0.2-0.9 0.1-0.4 0.4-0.8 0.4-0.3 0.8-0.4 0.4-0.2 0.8-0.2zm6.9-54.5c0.5-0.7 1.4-0.1 1.3 0.5 0 1.6 0.1 3.2 0.4 4.8 0.2 0.8 0.4 1.5 0.8 2.2l0.1 0.2c0.5 0.9 0.8 1.8 0.2 2.7-0.3 0.5-0.8 0.8-1.3 0.8-2.5-0.1-2.8-3.5-3-5.4-0.1-2 0.4-4.2 1.5-5.8z"/>
14
+ </g>
15
+ <g id="head/No-Hair-3">
16
+ <path id="🎨-Background" fill-rule="evenodd" class="s0" d="m128.9 29.6c-7.5-19.5-20.9-33.8-43.5-24.8-0.6-0.5-1.5-0.6-2.3-0.1-12.3 7.7-21.1 20.1-25 34.1-2.3 0.4-4.6 1.2-6.6 2.5-4.4 2.8-7.4 7.2-10.2 11.4-0.8 1.3 0 3.5 1.6 3.7q1 0.2 2 0.3-0.3 0.9-0.7 1.7c-1 1.9 0.9 3.9 2.7 3.4q0.3 0.1 0.6 0.2c0 1.1 0.6 2.6 1.7 2.8 1.7 0.4 4.1-1 3.7-3q0.8 0.1 1.6 0c0 1.1 0 2.2 0.2 3.1 0.4 4.5 4.9 7.5 9.2 6.2 0.3 1.4 0.6 3.3 2 4.1 1.6 4.5 4.4 9.7 8.9 11.8-0.4 1-0.2 2.3 1.1 3 8.3 4.7 18.3 6.3 27.8 4.6 3.8-0.3 7.4-1.1 11-2.9 2.5-1.4 4.9-3 7.2-4.8 2.3-1.7 4.8-3.4 6.6-5.7 2-2.4 3-5.3 3.6-8.3 2.8-14 1.8-27.6-3.2-40.9-6.3-16.4 6.2 14 0-2.4z"/>
17
+ <path id="🖍-Ink" fill-rule="evenodd" class="s1" d="m92.9 0.9c3.8-0.2 7.7 0.4 11.3 1.6 5.8 1.8 11.1 5 15.5 9.2 4.5 4.4 7.8 9.7 9.8 15.6 2.4 7.1 2.8 14.7 3.5 22.1 0.3 3.8 0.9 7.5 1.5 11.2l0.1 0.6c0.6 3.6 0.9 7.3 0.1 10.9-1.3 6-5.3 11.1-10.1 14.8-9.7 7.8-24.8 12.5-36.2 5.4-1.7-1.1-0.1-3.9 1.6-2.8 1.2 0.8 2.5 1.5 3.9 2 5.7 2.1 12 1.3 17.6-0.6 5.6-1.8 10.9-5 15.1-9.2 4.3-4.5 6.7-10 6.3-16.2-0.2-3.7-1-7.3-1.5-11-0.4-3.3-0.7-6.6-1-9.8l-0.1-1.2c-0.6-6.7-1.4-13.5-4.5-19.6-2.5-5.1-6.3-9.6-10.8-13.1-4.7-3.7-10.3-6.2-16.2-7.2-6.9-1.1-13.5 0.9-19.3 4.7-5.1 3.4-9.5 7.9-12.9 13-1.7 2.5-3.1 5.2-4.3 7.9-1.1 2.5-1.9 5.2-2.8 7.9q1.1-0.1 2.3 0.1c4 0.4 7.7 2.5 10 5.7 2.9 4 2.2 8.9 3.3 13.4 0.1 0.3-0.1 0.7-0.4 0.9-1.7 1.1-4 1.1-5.6-0.1-1.5-1.1-2.1-3.1-1.6-4.8 0.1-0.2 0.4-0.1 0.4 0.1 0.2 2.9 2.8 5.1 5.5 3.8-1.1-3.9-0.5-8.3-2.9-11.8-4.1-6.3-12.5-6.5-18.5-3-3.1 1.8-5.6 4.6-7.5 7.7l-0.5 0.9c-0.7 1.2-1.5 2.6-1.6 3.9-0.1 0.8 0.2 1.5 1.1 1.1 0.7-0.3 1.2-1 1.7-1.6 0.7-1.1 2.3-0.2 1.7 1-0.8 1.5-1.4 3.2-1.5 5v0.5c0 0.3 0 0.8 0 0.9 0.1 0 0.8-0.7 0.9-0.8 0.5-0.5 1-0.9 1.7-1 0.9-0.2 1.8 0.9 1 1.7-0.7 0.6-0.7 1.9 0.1 2.4 1.1 0.9 2.5-0.5 2.7-1.6 0.1-1.2 1.8-1.3 1.8 0 0.2 2.6-2.9 4.9-5.4 3.5-0.9-0.5-1.5-1.5-1.7-2.5q-0.5 0.2-1 0.3c-1.1 0.1-1.9-0.7-2.1-1.8-0.2-1.2-0.1-2.6 0.2-3.8-0.6 0.1-1.2 0-1.9-0.3-2-1.2-1.4-3.7-0.6-5.4 3.1-7.3 9.7-13.9 17.8-14.4 0.1-1.3 0.3-2.5 0.5-3.8 2.8-12.6 11.9-24.2 23.6-29.7 3.1-1.4 6.5-2.4 9.9-2.7zm-30.8 50.3h0.1c1.3-0.3 4.6-0.6 4.2 1.5 0 0.1-0.1 0.1-0.2 0-0.3-1.3-3-0.2-3.8 0.1-1.1 0.4-2.1 1.1-3 1.8-2 1.7-3.2 4.1-3.4 6.6-0.2 2.6 0.5 5.3 2.3 7.2 0.9 0.9 2.1 1.5 3.4 1.5 1.1 0.1 2.4-0.8 3.5-0.3 0.2 0.1 0.3 0.4 0.3 0.6 0 0.4-0.2 0.8-0.5 1.1 1.8 3.2 3.2 6.7 5.5 9.6 1.2 1.5 2.5 2.9 3.9 4.1q1.1 0.8 2.3 1.4c0.9 0.5 1.7 0.9 2.3 1.7 0.6 0.7 0 2.2-0.9 2.3-2.2 0.3-4.3-1.5-5.8-2.8-1.6-1.3-3-2.9-4.1-4.6-2.2-3.3-3.7-7.2-4.3-11.1-0.7 0.2-1.5 0.2-2.1 0.2-1.5 0-3-0.5-4.2-1.5-4.5-3.4-5-10.6-1.9-15.1 1.6-2.1 3.9-3.7 6.4-4.3zm0 8.3c1.1-0.1 2.1 0 3.1 0.4l0.4 0.1c0.9 0.4 1.8 0.7 2.4 1.4 0.9 0.9 0 2.6-1.4 2.3-1.4-0.5-2.6-1.7-4.1-2.2-1.3-0.5-2.8-0.4-4 0.4-0.2 0.1-0.4-0.1-0.3-0.3 0.9-1.4 2.4-2 3.9-2.1z"/>
18
+ </g>
19
+ <g id="face/Smiling">
20
+ <path id="🖍-Ink" fill-rule="evenodd" class="s1" d="m109.2 79.3c-1.5-0.6-2.7-1.6-3.7-2.8-0.3-0.4-0.4-0.9-0.3-1.3 0.1-0.5 0.4-0.9 0.7-1.2 0.4-0.3 0.9-0.4 1.3-0.3 0.4 0 0.8 0.2 1.1 0.7l0.1 0.1c0.6 0.7 1.3 1.3 2.1 1.7 0.8 0.4 1.7 0.6 2.6 0.5 1.7-0.2 2.9-1.1 4.2-2.4q0.2-0.3 0.5-0.5 0.1-0.2 0.3-0.3 0.3-0.1 0.6 0 0.3 0.1 0.4 0.3 0.2 0.2 0.2 0.5c-0.2 1.4-0.9 2.5-1.8 3.5-1.1 1-2.6 1.7-3.9 2-1.5 0.2-3.1 0-4.4-0.5zm5.9-21.6c8.1 1.4 3.9 15.4-6.5 7.7-1.2-1 0.3-3.2 1.6-2.3 1.5 1.1 4.4 3.5 6.4 1.4 1.7-2.4-0.7-4.7-2.3-5.6-0.4-0.3-0.1-1.3 0.8-1.2zm-19.4-7.8c0.2-2.1 3.5-2.6 3.9-0.5 0.2 2-0.1 3.7-1 5.5-0.8 1.7-2.9 0.9-3.1-0.6-0.2-2.1 0.1-3 0.2-4.4zm25.4-0.9c0.4-0.6 1.1-1.1 1.9-0.8 2.5 0.7 1.8 4.3 0.9 6-0.5 1-2 1.2-2.7 0.4-1.2-1.4-1.7-4.1-0.3-5.4q0.1-0.1 0.2-0.2zm-22.5-8.6l0.4-0.1c1.2-0.2 2.7-0.4 3.6 0.6 0.5 0.5 0.6 1.5 0 2-1.1 0.8-2.3 0.5-3.6 0.6q-1.6 0.1-3.1 0.5c-2.3 0.7-4.2 1.8-6.1 3.2-0.3 0.1-0.5-0.2-0.4-0.4 1.1-2.2 3.3-4 5.5-5.1 1.1-0.6 2.4-1.1 3.7-1.3zm20.2-1h0.3c3.3 0.7 7.6 2.1 9.2 5.4 0 0.4-0.1 0.5-0.1 0.6-0.1 0.1-0.1 0.1-0.3 0.2q-0.1 0-0.2 0c-0.7-0.2-1.2-0.5-1.8-0.8l-0.6-0.3c-0.7-0.3-1.4-0.6-2.1-0.9q-2.4-0.7-4.9-1-0.5-0.1-0.9-0.4-0.4-0.3-0.6-0.8c-0.1-0.5-0.1-0.8 0.2-1.3q0.3-0.4 0.8-0.6 0.4-0.2 1-0.1z"/>
21
+ </g>
22
+ <g id="facial-hair/Moustache-9">
23
+ <path id="🎨-Background" fill-rule="evenodd" class="s0" d="m122.4 67.4c-2.9-0.5-6 0.3-8.9 1-4.5-2.9-10.4 0.1-13.7 3.8-1.1 0.9-3.4 2.1-2.2 3.9-0.4 1.2-0.6 1.8 0.4 0.4 5.5 0.6 11.3-0.6 16.7-1.7 1.9 0.6 3.5 2 5.5 1.5 1.9 0.4 4 0.8 5.7-0.4 1.4-0.1 4.3 2.3 4.2-0.4-0.4-2.7-5.6-7.1-7.7-8.1z"/>
24
+ <path id="🖍-Ink" fill-rule="evenodd" class="s1" d="m131.1 78c-3.8-2.7-9.3 2.1-16.1-2.4-3.5 2.9-13.1-0.1-18.7 3.1-4.5 1 5-10.9 6.7-11 4-2.4 7.3-1.6 11.3-0.1 1.3 0.1 2.8-0.8 4.1-1 6.7-1 11.5 5.1 13.9 10.5 0.4 0.8-0.5 1.6-1.2 0.9zm-1.2-2.3c-2.2-4.5-6.7-9.1-12.2-7.8-0.3 0.1-3.9 1.4-3.2 0.8-7.9-2.8-13.1 0.3-16.8 7.6 3.9-1.3 8.1-1 12.1-1.1 1.2 0 3.5 0.3 4.2-1 0.1-0.4 0.4-0.5 0.7-0.4 0.2-0.2 0.5-0.2 0.8 0 2.7 1.9 5.9 2.4 9.1 2.1 1.8-0.2 3.6-0.6 5.3-0.2z"/>
25
+ </g>
26
+ <g id="accessories/Glasses-3">
27
+ <path id="🖍-Ink" fill-rule="evenodd" class="s1" d="m139.2 45.7c-0.9 0.4-1.5 1.3-1.2 2.3 0.1 0.8-0.2 1.4-0.7 1.7-0.1 4.7-0.9 10.1-4.6 13.6-8.6 5.6-17.1-1.3-15.3-12.2q-0.2-0.1-0.3-0.3-0.1-0.2-0.2-0.3c-0.1-0.2-1.5-0.7-3.3-0.4-1.8 0.2-2.4 1.1-3.3 2-0.1 0.3-0.4 0.5-0.7 0.6-0.8 4-1.5 8.4-4.6 11.4-7.7 7.2-21 1.3-20.5-9.7-2.7-0.5-0.4-3.6-4.7-4.3-0.7-0.3-1.4-0.7-1.9-1.3-6.4-0.7-12.6-0.4-18.7 1.8-2.5 1-5.7 1.5-4.3 5.1 0 1-1.2 1.6-2 0.8q0 0 0 0c-4.2-7.5 4.1-8.7 10.1-9.6 3.3-0.7 6.6-1 9.9-1 1.5 0.1 3.5 0 4.9 0.4q0 0 0 0c1.4-4.2 30.7-5.2 32.4 1.8 2.2 0 3.9 0.6 5.8-0.1 0.6-5.1 14.5-7.1 20.5-5.7q0.7 0.1 1.3 0.2 0.3 0.1 0.5 0.2 0.2 0 0.5 0.1c1.3 0.2 1.5 2.3 0.4 2.9zm-31.3 5.9c-2.4-2.1-3.7-4.1-8.4-4.4-3.7 0-7.7-0.1-11 2-2 1-1.6 3.9-3.2 5 1.7 13.1 18.7 16.6 21.8 2 0.4-1.5 0.7-3.2 0.8-4.6zm27.3-2.3c-1.9-1.9-0.7-4.5-4.9-4.1-12.1 0.7-8.3 7.8-11.8 6.8 0.2 4.6 1.8 10.6 7.1 11.1 2.4 0.2 5.1-0.4 6.5-2.3 2.4-3.3 3.1-7.6 3.1-11.5z"/>
28
+ </g>
29
+ </g>
30
+ </g>
31
+ </g>
32
+ </g>
33
+ </svg>
@@ -0,0 +1,30 @@
1
+ <svg version="1.2" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 249 232" width="249" height="232">
2
+ <title>character-02</title>
3
+ <style>
4
+ .s0 { fill: #ffffff }
5
+ .s1 { fill: #000000 }
6
+ </style>
7
+ <g id="Introduction">
8
+ <g id="variations">
9
+ <g id="images">
10
+ <g id="a-person/bust">
11
+ <g id="body/Whatever">
12
+ <path id="🎨-Background" fill-rule="evenodd" class="s0" d="m234.9 146.9q3.3-1.7 6.4-3.6c1.4-0.9 0.1-3.1-1.4-2.3q-1.1 0.6-2.3 1.2 0.9-0.7 1.7-1.7c1.9-1.7-0.6-5-2.8-3.6-1.9 1.4-3.9 2.9-6.1 3.8-4.6 2-9.7 2.3-14.7 2.3-1.8-0.1-3.5 0.2-5.3 0.6 0.7-2.8 2.4-4.9 3.3-7.6 0.7-2.7-3.2-4.5-4.6-1.9q-0.5 0.9-0.9 1.9c-3 2.7-8 2.5-11.1 5.4-1.7 1.5-2.5 3.6-2.8 5.7-0.3 1.4 0.1 2.8-0.8 4.1-4.1 5.8-10.6 15-13.9 21.4-2.4-15.2-8.6-34.1-15.1-48-2.1-4.5-4.6-8.9-7.8-12.6 0.4-1.3-0.9-3.5-1.7-2.9-2.5-3-7-3.8-10.5-5.4-4.9-2-8.9-6.3-10.8-11.2-2.6-9.3-8.8-10.4-17.4-10-8.3 0-14.4 3.5-16.2 11.9-3.6 6.4-12.3 5.3-18.5 7-4.6 1.1-9 2.7-13.2 4.7-4.7-4.4-21.4 14.2-22.9 19q1.3 0.2 2.7 0.6c0.7 0.3 0.4 1.4-0.4 1.3q-1.5-0.4-3-0.6 0 0.2 0 0.3-0.2 0-0.4 0 0.4 0.2 0.7 0.5c0.6 0.4-0.1 1.3-0.7 1-0.6-0.5-1.3-0.4-2-0.5 0 1.4-5-0.2-5.8-0.7-3.4-0.4-6.9 0.1-10.1-1.6-4.3-0.9-8.5-1.9-12.8-3-1.1 0.4-2.1 2-1.2 3.1 0.5 0.5-0.2 1.4-0.8 1-2.1-1.2-3.7-3.1-5.1-5.2-0.6-0.7-1.8-0.5-2.7-0.8q-0.1 0.3-0.2 0.7c-3.6 0.6-1 4.6 0.8 5.9-0.9 0.6-1 1.9-0.9 2.9-0.2 0.4-0.3 0.9-0.1 1.3 0.7 1.6 2.2 2.9 3.4 4.2 1.2 1.5 2.3 2.9 3.9 4.1 5.8 4.4 12.9 6.9 20.1 7.9 2.6 0.4 6.3 1 7.9 3.2-0.4 2.5-1.1 5-1.8 7.5-0.9 3.4-0.8 6.9-0.8 10.3-0.2-0.1-0.4-0.1-0.4 0.1-0.3 1.4-0.4 2.9-1.3 4-0.7 2.2-1.2 4.6-1.5 6.9-1.1 11-1.4 22.3 1.1 33.1 1 4.1 2.6 7.9 4.8 11.4 0.6 1 1.7 1.3 2.6 1.1 3.1 1.7 7.1 2.2 10.5 1.8 11.5-3.3 7.4 4.5 23.6 2.1 27.8-3.5 55.9 3.5 83.7-0.6 0.7 5.3 9.6 3.7 12.7 1.5 9.3-6.9 14-28.9 18.7-40 3.2-8.8 8.6-24.3 15.6-30.2 2.1-1.7 4.7-2.6 7.2-3.3 9.6-2.4 19.2-4.7 28.7-7.1 1.7-0.4 1.4-3.2-0.4-3q-3.4 0.3-6.9 0.6z"/>
13
+ <path id="🖍-Ink" fill-rule="evenodd" class="s1" d="m22.4 145.3c-0.7-0.1-1.3-0.3-1.9-0.5q-1.5-0.4-2.9-1c-1.9-0.7-3.7-1.7-5.5-2.8-2.8-1.8-5.3-4.1-7.1-6.8l-0.2-0.2c-1-1.7-3-5.3-0.8-6.5-1.4-1.2-2.8-3.3-2.7-5 0.1-2.3 3-2.3 4.5-1.3 0.9 0.6 1.7 1.5 2.4 2.4q1.2 1.5 2.6 2.9 0.3 0.4 0.7 0.7l0.2 0.2q0-0.1-0.1-0.2c-0.5-1.6 0.1-3.6 1.7-4.3 0.9-0.4 1.9-0.2 2.8 0.2l0.1 0.1q1.9 0.7 3.8 1.3c5.2 1.5 10.6 1.7 16 2.4 2.1 0.3 4.2 0.7 6.2 1.2 0.8-3.3 2.7-6.5 4.8-9.1 9.9-12.5 26.4-16.7 41.4-19.4 1.3-0.2 2.5 1.6 3.3 1.2 1.5-0.8 2.8-2 4-3.2 2.5-2.7 4.2-5.8 6.3-8.8 1-1.5 3.4-0.2 2.4 1.4l-0.4 0.8c-2 3.1-4.1 6.4-6.8 8.8-1.5 1.3-3.1 2.4-5 3-1.4 0.5-3.3 0.9-4.9 0.4l-0.2-0.2q0.1 0.1 0.2 0.2c4 5.8 9.1 10.8 14.4 15.4 5.3 4.7 11.1 8.9 16.9 13l0.5 0.3c9.5-6.9 17.5-15.9 23.1-26.2-1.2-0.1-2.3-0.9-3.3-1.4-1.3-0.7-2.4-1.5-3.3-2.6-1.9-2.4-1.7-5.4-2-8.3 0-0.1 0.2-0.2 0.3-0.1 1.1 0.9 1.4 2.3 1.9 3.5 0.4 1.4 1 2.5 2.1 3.5 1 0.8 2.3 1.5 3.5 2.1 0.6 0.3 3.7 1 4.1 1.7 5.4-1.3 10.6 0.9 14.6 4.6 3.9 3.6 6.7 8.2 9.2 12.8 2.7 4.8 4.9 9.9 6.8 15.2 1.9 5.3 3.3 10.7 4.1 16.3 0.7 4.7 1.1 9.5 1.4 14.3v0.5q6-9.3 12.3-18.6c-1-2.5 0.1-5.1 1.9-7 1.9-2.2 4.7-3.2 7.3-4.4l0.3-0.1c1.3-0.6 2.5-1.2 3.6-2.1 1-0.8 1.8-2 2.9-2.7 1.6-1.1 4.5-0.9 4.6 1.5 0 1.4-0.5 2.8-1.1 4-0.6 1.4-1.4 2.6-2.3 3.7q-0.1 0.1-0.2 0.2c1.3 0.2 2.6 0.4 4 0.4 2.7 0.2 5.5 0 8.1-0.6 2.8-0.6 5.4-1.6 7.9-2.9 2.1-1.1 4-2.6 6.4-2.9q0.3-0.1 0.7-0.1c0.3 0 0.7 0.4 0.6 0.8q-0.2 0.3-0.3 0.6c-0.8 1.8-2.1 3.6-3.7 4.9l-0.1 0.1q0.9-0.3 1.7-0.6c3.1-1.5 6-3.6 9.4-4.5q0.2 0 0.5-0.1c1-0.2 1.6 0.9 1 1.7q-0.2 0.2-0.3 0.4-2.3 2.8-5.1 5.2-0.9 0.8-1.9 1.5 3.1-0.9 6.1-2.2c0.8-0.3 1.4 0.5 1.5 1.2 0.3 2.2-2.2 3.8-3.8 4.9-1.6 1-3.3 1.9-5.2 2.5-3.5 1.3-7.1 1.9-10.8 2.4l-1.8 0.2c-7 1-14.3 2.2-19.4 7.7-2.8 3-4.7 6.8-6.5 10.6-1.7 3.7-3.3 7.6-4.7 11.4-1.5 4-2.8 8.1-4.2 12.2-1.3 3.7-2.9 7.3-4.4 11l-0.2 0.5c-3.2 7.8-7.1 15-12.5 21.5-0.9 1-2.3-0.5-1.5-1.5 5.6-7.3 9.6-15.8 12.8-24.4 1.5-3.8 2.7-7.8 4.1-11.7l0.8-2.3q1.7-4.7 3.5-9.3c1.5-3.9 3.1-7.7 5-11.4l0.2-0.4c1.8-3.6 4-7.1 7-9.8 5.4-4.9 12.6-6 19.6-7l2.2-0.3c2.9-0.3 5.9-0.8 8.7-1.6 1.7-0.4 3.3-1 4.8-1.8q0.9-0.5 1.8-1-2.5 0.7-5 1.1-1.2 0.3-2.4 0.4c-2.1 0.2-4.2 0.2-6.3 0.1-0.2 0-0.3-0.3-0.1-0.4q2.3-0.4 4.5-0.9l0.4-0.1q0.1-0.4 0.4-0.8c0.7-0.9 2.1-1.4 3.1-2q1.5-1 2.9-2.1 1.3-1.1 2.5-2.3 0 0 0 0c-2.1 1-4.2 2.3-6.4 3.1-1.8 0.6-3.7 1-5.6 1.2h-0.1-0.1c-2 0.1-4 0.1-5.9 0.5-0.2 0.1-0.3-0.2-0.1-0.3 1.7-0.7 3.5-1 5.2-1.3q0.1-0.2 0.4-0.4l0.4-0.2c1.4-0.6 2.6-1.3 3.8-2.4q1.5-1.4 2.4-3.2c-2.5 0.6-4.7 2.4-6.9 3.5-2.5 1.2-5.1 2-7.8 2.5h-0.3c-5 0.9-11.1 0.8-15.6-1.9-0.1 0 0-0.2 0.1-0.2 1.3 0.2 2.6 0.4 3.8 0.7-0.2-0.3-0.3-0.7 0-1 1.1-1.3 2-2.8 2.6-4.4l0.1-0.3c0.2-0.8 0.7-2 0.2-2.6-0.4-0.7-1.4-0.6-2-0.3-1.3 0.6-2.2 2-3.2 2.9-1.2 0.9-2.5 1.6-3.9 2.2l-0.3 0.2c-2.3 1-4.9 1.9-6.7 3.8-1 1-1.9 2.3-2.2 3.7q-0.2 0.9 0.1 1.9c0.1 0.5 0.4 0.8 0.2 1.3-0.2 0.7-0.9 1.5-1.3 2.1q-0.7 1-1.4 2-1.4 2-2.7 4.1-2.7 4.1-5.4 8.2-0.8 1.3-1.7 2.7l-0.8 1.3h-0.1q-0.2 0.4-0.4 0.7l0.4-0.7q0 0 0.1 0v0.2c0 0.7-0.4 1.1-1 1.2q0.1 0 0.1 0l-0.4 0.5q0.1 0.2 0 0.4c-0.1 0.3-0.4 0.6-0.7 0.8-4.5 7.1-9 14.3-13.4 21.5q-0.4 3.2-0.7 6.5c-0.4 4.9-0.7 9.9-0.8 14.9-0.1 2.4 0.1 4.8 0.2 7.2q0.1 1.7 0.2 3.4l0.1 0.8c0.1 1.1 0.1 2.2-0.3 3.3-0.3 0.9-1.4 1.1-2.1 0.4q-12.5-0.5-25-0.7c-15-0.3-29.9-0.3-44.9 0q-11.3 0.2-22.6 0.6c-3.7 0.2-7.4 0.3-11.1 0.4-2 0-5.1-0.7-5.3-3q-0.3 0.1-0.7 0.1-0.2 0.1-0.4 0c-3 0.9-6.8-0.4-9.6-1.1l-0.2-0.1c-2.7-0.7-4.9-1.7-6.7-3.9-3-4-4.1-9.2-4.7-14.1-0.5-4.5-0.5-9.2 0.1-13.7-0.3-3.7 0-7.6 0.4-11.3q0.3-2.7 0.8-5.4 0.2-1.5 0.6-3c0.1-0.4 0.1-0.9 0.2-1.3l0.1-0.1q-0.5 0-1.1-0.3c-0.8-0.4-1.1-1.4-1.1-2.3 0-2.7 0.3-5.5 0.6-8.2q0.4-4.1 1.2-8.1l0.1-0.7c0.4-2 0.9-4.1 1.7-5.9-3-0.6-6-1.1-8.9-2q-2.1-0.7-4.1-1.7zm158.9 25.4q-0.2 0.3-0.4 0.7l0.4-0.7q0 0 0 0zm58.5-24.5q0 0 0 0-0.1 0.1-0.1 0.1 0 0 0.1-0.1 0 0 0 0zm-0.7 0.6q-0.1 0-0.2 0.1 0.1-0.1 0.2-0.1zm-0.3 0.2q0.1-0.1 0.1-0.1zm4.1-6.4q0.2-0.1 0.3-0.2zm-3.3 5.7q-0.3 0.2-0.6 0.4 0.3-0.2 0.6-0.4zm-61.7 27.4q0 0-0.1 0c-1.2 0.3-2.4 0.6-3.6 0.9-2.1 0.5-4.1 1.1-6 2-0.4 5.1-1 10.2-1.6 15.3l-0.1 1q1.3-2.4 2.7-4.8 4.3-7.3 8.7-14.4zm-160-31.4q-0.2-0.2-0.4-0.4c-1.2-1.1-2.2-2.3-2.9-3.7l-0.2-0.4c-0.6-1.2-1.4-2.8 0.1-3.7 0.8-0.5 1.8-0.3 2.8 0q0.1 0 0.2 0 0.6 0.3 1.2 0.5c1.5 0.7 2.9 1.8 4.4 2.7 1.6 1 3.1 1.7 5 2.1h0.1c1.7 0.3 3.6 0.5 4.8 2 0.3 0.3 0 1-0.5 0.8-3.3-1.1-6.8-1.4-9.8-3.2-1.3-0.7-2.5-1.6-3.8-2.3q-1-0.6-2.1-1l-0.4-0.1c-0.2-0.1-0.5-0.1-0.7-0.1-0.4 0.2-0.3 0.4-0.1 0.7 0.9 2.8 3.4 5.1 5.7 6.6q0.8 0.5 1.7 1c3.8 2 8.1 3 12.2 4.1q2.4 0.7 3.2 0.9c0.9-0.1 2 0.2 2.6 0.6q1 0.6 1.6 1.5c0 0 0.4 0.3 0.5 0.8q0.3 0.7 0.4 1.4 0 0.5-0.2 0.7c0.4 6.7-1.4 13.3-3.4 19.6l-0.2 0.6-0.1 0.4c-2.2 6.7-4.7 13.3-5.8 20.3-0.8 4.6-0.7 9.5-0.2 14.1v0.4c0.6 4.4 1.6 9.3 4.4 12.9 1.5 1.8 3.2 2.6 5.3 3.2h0.2c1.9 0.6 3.9 1.3 6 1.5 1.9 0.2 3.4-0.5 5.1-1.1 3.6-3.2 5.2-7.8 6.4-12.4 3.1-12 2.7-24.5 1-36.7-1-6.3-2.2-12.6-3.4-18.9-0.7-3.2-1.3-6.3-1.9-9.5l-0.3-1.9q-0.3-1.5-0.5-3.1c-0.2-1.4-0.3-2.7-0.4-4.1-1.7-2.9-4.2-5.2-7-6.9-2.1-1.2-4.3-2-6.5-2.6-6.4-1.7-13.4-1.6-19.9-2.9-2.2-0.5-4.2-1.1-6.3-1.9l-0.3-0.2c-0.9-0.3-1.9-0.5-2.3 0.6-0.4 0.8-0.2 1.6 0.3 2.3 1.3 1.6 3.7 2.4 5.6 2.9q1.7 0.6 3.4 0.9c1.2 0.2 2.3 0.3 3.4 0.7 0.4 0.1 0.5 0.8 0 0.9-1.4 0.3-2.8 0.1-4.2-0.2q-2.3-0.5-4.5-1.3-0.4-0.1-0.8-0.3l-0.2-0.1q0.3 0.3 0.6 0.5c0.1 0 0 0.1 0 0.1-3.5-1.3-6.6-3.6-9-6.3l-0.2-0.2c-0.8-1-2.8-3.9-4.4-3.1-1.6 0.8 1.1 3.8 2.1 5l0.1 0.1c1.1 0.1 2.2 0.8 3.1 1.3 1.6 1 3.3 1.9 5 2.7 3.4 1.6 7 2.7 10.3 4.4 0.1 0 0.1 0 0 0-2.1-0.3-4.2-0.8-6.3-1.5h-0.1l-0.1-0.1q-1.9-0.6-3.8-1.4-2.1-0.8-4-1.9c-1.2-0.7-2.6-1.8-3.9-2q-0.3 0-0.4 0c-1.6 0.1-0.3 2.7 0.1 3.5q1.1 2 2.6 3.6c2.1 2.2 4.5 4 7.2 5.3q1.4 0.7 2.8 1.3zm26.7-6.1q1.9 0.2 3.7 0.9h0.1c0.9 0.4 2.2 0.8 2.5 1.7 0 0.3-0.2 0.5-0.4 0.5-1 0.1-2.1-0.9-3-1.3q-1.4-0.5-3-0.8c-2.3-0.3-4.8-0.1-6.9 0.8-0.2 0-0.3-0.2-0.1-0.2 2.2-1.2 4.6-1.8 7.1-1.6zm-9.9 38c0 0.6-0.2 1.2-0.2 1.8q-0.2 1.4-0.3 2.8-0.4 2.9-0.6 5.7-0.1 1.9-0.2 3.7c1.2-4.5 2.8-8.8 4.3-13.2q-0.4-0.1-0.8-0.2l-0.4-0.1c-0.3-0.1-1.1-0.3-1.8-0.5z"/>
14
+ </g>
15
+ <g id="head/hat-beanie">
16
+ <path id="Path" fill-rule="evenodd" class="s0" d="m119.3 2.5c9.5 0 20.8 4.5 21.8 4.6q0.8 0 6 4.6l-3.8 7.3 0.3 0.3c1.5 1.4 2.7 2.6 3.7 3.6 8 8.2 9.4 40.3 7.5 51.4-1.9 11.2-5.3 22.2-21.6 22.2-16.2 0-34.2-9.8-37-12.8q-2.8-3.1-6.3-3-0.1-0.1-0.3-0.3l-0.3-0.1q-4.8-0.7-6.9-1.8c-2.7-1.6-5.6-9.6-5.6-11.4 0-1.7-4.5-14.5-4.6-15.9 0-1.1-5.8-6.3-5.8-8 0-1.6-1.1-1.5 0-7.3l0.4-1.7c1.2-6.2 3.6-16.5 12.9-20.9 10.2-4.9 30.1-10.8 39.6-10.8z"/>
17
+ <path id="🖍-Ink" fill-rule="evenodd" class="s1" d="m78.1 13.1c5.1-5.5 34-13.8 48.6-12h0.5q1.7 0.2 3.4 0.7c3.7 0.9 7.5 2.2 10.5 4.3 2.5 1.8 10.5 4.7 8.2 9.3 0.8 1.7 1.2 3.7 0.6 5.3-0.1 0.6-0.3 1.1-0.5 1.7 1.9 2.7 3.3 5.8 4.5 8.8 2.1 7.4 3.4 15.2 3.6 22.8 0.6 14.4-0.9 31.6-13.5 41-7.6 5.9-19.5 6.1-28-1.3-0.5-0.5-2.8-2.1-2-2.4q0.3 0.4 0.7 0.7 0 0 0 0l-0.2-0.2c-0.5-0.4-1-1-0.4-0.9q0.1 0.1 0.1 0.1 0.2 0.1 0.3 0.2v0.1-0.1c-0.3-0.3-0.5-0.7 0-0.5l0.1 0.1q0.3 0.3 0.7 0.7 0-0.1 0-0.1l-0.2-0.2c-0.2-0.2-0.2-0.2-0.1-0.4-0.5-0.7 0.4-0.3 0.5 0 0.5-0.2 1 0.9 1.4 1 15.6 12 38.3 1.4 37.9-32.1v-0.7c-0.1-10.7-1-21.7-5.4-31.4q-0.7-1.4-1.5-2.7-0.5-1-1.1-2-1.8-0.1-3.5-0.6-0.6-0.2-1.2-0.4c-5.7 0.4-11.2 0.7-16.9 1l-1.8 0.1c-4.8 0.3-9.8 0.8-13.7 3.8-3.8 2.7-3.8 8.1-7.1 11.1-4.7 3.1-4.7 6-5.6 10.7 0.1 3.5 2.5 8.6-2 10.1 0.8 1-0.3 0.5-0.4 0.1q0 0.1 0 0.1c0.7 1.2-0.3 0.4-0.4 0q-0.1 0-0.1-0.1c0.6 1.1-0.5 0.3-0.4 0.1-1.3-2-4-2.3-5.9-1.8 0 0.1-0.1 0.1-0.2 0.1-8 1.7-6 18.5 2.3 16.8 0.4 0 0.4 0.1 0.4 0.2-0.2-0.5 0.4-0.3 0.4-0.2 0 0 0 0 0 0-0.1-1.1 0.9 0.4 0.8 0.5q0.1 0 0.1 0v-0.1c-0.2-0.5-0.2-0.3-0.2-0.6-0.1-0.3-0.1-0.2-0.1-0.4 0.5-0.3 0.6 0.7 0.8 0.8-0.3-0.3-0.1-0.6 0.2-0.4 1.8 3.9 4.2 7.6 7.3 10.5q0.5 0.4 1.1 0.8c1.3 1.1 3.3 1.8 4.6 2.9q0 0 0 0v0.1l0.4 0.2q0.2 0.2 0.4 0.4 0.1 0.1 0.3 0.4c0 0.1-0.1 0.2-0.3 0.1q-0.1 0-0.2 0 0 0 0 0c0.1 0 0.2 0.4 0 0.3q-0.1 0-0.3-0.1 0.2 0.2 0.3 0.4 0.2 0.2 0.2 0.4 0 0.1-0.1 0.1-0.2 0-0.4-0.1l0.1 0.1c0.1 0.1 0.2 0.4 0 0.3q-0.3-0.1-0.6-0.2 0 0.1-0.1 0-0.8-0.3-1.6-0.7-0.7-0.5-1.4-1-0.6-0.4-1.2-0.9c-2.7-1.7-5.1-3.9-6.9-6.3-3.1 2.7-9.3 0.1-13.2-2-3.4-1.9-4.7-5.4-5-9.1-0.8-5.1-4.9-6.8-4.6-17.9q0 0 0 0-0.2 0-0.4-0.2-0.3-0.1-0.4-0.2l-0.2-0.2q-0.1-0.1-0.2-0.1c-0.1 0.1-0.1-0.1-0.1-0.1l-0.2-0.4c-0.7-0.8-1.4-1.8-1.9-2.6q-0.1 0.1-0.1 0.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0c-1.3-1.9-2.6-4.3-2.9-6.6-0.4-1.7-0.3-3.5 0.1-5.1 1.5-5.7 6.6-18.5 13.3-24zm-10.5 35.7q0 0 0 0 0 0 0 0zm47.2 42.7l-0.1-0.1 0.1 0.1q0.1 0.1 0.1 0.2 0-0.1 0-0.1 0 0-0.1-0.1zm11.9-87.6c-9.9-0.8-19.7 1.3-29.1 4l-0.7 0.2c-5.4 1.5-11.1 2.9-15.6 6.2-6.4 4.8-9.6 12.6-12.5 19.7-2.5 5.3-1.2 11.3 2.6 15 0.3-3.7 1-7.2 2.1-10.8 0.2-0.5 0-0.7 0.5-0.8 0.7 9.6-2.8 16.6 4.1 28 3 5.3-0.5 9.2 8 12l0.2 0.1c1.8 0.7 3.7 1.2 5.4 0.8l-0.1-0.2c-0.2-0.3-0.2-0.4 0-0.5q0 0 0 0-0.3-0.6-0.5-1.1-0.1 0-0.3 0c0.1 0.1 0.1 0.2 0 0.3q-0.7 0.2-1.5 0.1h-0.1c-0.5 0-0.9-0.1-1.2-0.2q-0.1 0-0.3 0c-1-0.3-2.1-0.8-2.7-1.4-7.9-4.4-7.1-19.6 2.6-21 0.2-9.6 4.7-25.6 12.2-34.7 6.8-8.4 25.4-12 38.3-10.7q0.3 0.1 0.6 0.2c2 0.1 3.9 1 5.9 1.4-1.5-1-3.1-1.7-4.8-2.4-3.3-2-7.1-3.1-10.8-3.9q-1.1-0.3-2.3-0.3zm-39.6 58c0.6-0.2 0.5 0 0.6 0 3.8-0.4 7.8 2.9 9.9 5.6-0.2 0.2-0.6-0.3-0.7-0.4q0 0-0.1 0l0.1 0.1c0.8 1.2-0.8-0.2-1-0.5q0 0-0.1 0c0.2 0.2 0.6 0.5 0.6 0.8h0.1c1.1 0.9 1 1.6-0.2 0.3q0.1 0.1 0 0.2h0.1c0.5 0.4 1 1.5-0.2 0.4 0.2 0.8-1.1-0.8-1.2-0.8-2.2-1.7-5.5-3.5-8.3-3.7h-0.1c-0.6-0.1-0.8-0.2-0.6-0.6-0.7-0.1-0.5-0.4-0.2-0.4-0.5-0.3-0.1-0.6 0.2-0.5-0.2-0.5 0.5-0.1 0.6-0.2 0.4-0.6 0.5-0.1 0.5-0.3zm-7.8-30.7c1.8-0.6 7.1 1.3 6.7 3.9-0.3 0.6-1.1 1-1.7 0.6l-0.7-0.5c-1.4-0.9-2.6-1.6-4-2.4-0.8-0.4-1.1-1.2-0.3-1.6zm10.2-3.8l-0.7-0.5c-3.7-2.4-9-6.2 0.4-2.3 1 0.4 2.5 0.7 3 1.7 1 1.9-1.4 2-2.7 1.1zm0.4-11c-0.3-1.2 3.5 0.2 4.6 0.5l0.1 0.1c1.1 0.4 2.3 0.7 2.9 1.7 0.8 1.2-0.7 1.5-1.7 0.9-1.9-1.2-4-2.2-5.9-3.2zm9.5-5.3c-2.1-2.3 3.5-0.1 4.4 0.5 0.6 0.4 0.5 1.4-0.1 1.7-1.7 0-2.9-1.4-4.3-2.2zm9.6-2.5c-3.4-2.4 1-1.3 2.6-0.4 1 1-0.1 2.5-2.6 0.4z"/>
18
+ </g>
19
+ <g id="face/Tired">
20
+ <path id="🖍-Ink" fill-rule="evenodd" class="s1" d="m141.1 77.8c1.4-0.3 2.4 0.8 2.1 2.1-0.2 1.4-1.7 1.9-3 1.8-1.4 0-2.8-0.3-4.2-0.4q-2.2-0.1-4.4 0c-1.3 0-2.7 0.3-4 0-0.5 0-0.5-0.7-0.2-1 1.1-0.7 2.4-1 3.5-1.3q1.9-0.5 3.7-0.7 1.9-0.2 3.8-0.2c0.6 0 1.3 0.1 1.8 0 0.3-0.1 0.6-0.3 0.9-0.3zm-3-19.1c8.1 1.4 3.9 15.4-6.5 7.7-1.2-1 0.3-3.2 1.6-2.3 1.5 1.1 4.4 3.5 6.4 1.4 1.7-2.4-0.7-4.7-2.3-5.6-0.4-0.3-0.1-1.3 0.8-1.2zm-12.4-6.1c2.1-0.3 2.5 2.7 0.4 2.9q-0.7 0.1-1.3 0.1 0 0.3 0.1 0.5 0 0.2 0 0.4c0.1 0.7-0.5 1.5-1.1 1.9-0.6 0.3-1.5 0.4-2.2 0-0.3-0.3-0.6-0.5-0.8-0.9q-0.4-0.5-0.4-1.2c-1 0.2-2 0.6-3 0.8q0.1 0 0.1 0.1c0.1 0 0 0.1 0 0l-0.5-0.1q-0.2 0.1-0.5 0.1c-0.2 0-0.4-0.3-0.2-0.6 0.9-0.9 2.2-1.5 3.5-2l1.2-0.5c1.5-0.6 3.1-1.2 4.7-1.5zm17.2 1c1.4-0.2 2.8-0.1 4.2 0 2.3 0.1 1.3 3.5-0.6 2.7q0.1 0.2 0 0.4c0 0.6-0.2 1.1-0.8 1.4-0.5 0.4-1.2 0.3-1.7 0-0.5-0.3-0.8-0.7-0.9-1.3-0.1-0.5-0.1-0.9 0-1.3q0-0.2 0.2-0.4-0.2-0.1-0.4-0.1c-1.2-0.3-2.4-0.2-3.5-0.4-0.2 0-0.2-0.2-0.1-0.3 1.1-0.5 2.4-0.6 3.6-0.7zm-17.4-10.7c0.8-0.3 1.8 0.3 2.2 1 0.5 0.8 0.3 1.7-0.3 2.4-0.9 1-2.6 1.6-3.8 2.2l-0.1 0.1q-1.9 0.9-3.9 1.6c-1.3 0.5-2.7 0.9-4 1.2q-1.1 0.3-2.2 0.4c-0.6 0.1-1-0.1-1.6-0.1-0.1 0-0.1-0.1 0-0.1 0.5-0.3 0.9-0.8 1.4-1.1q0.9-0.4 1.8-0.9c1.2-0.6 2.3-1.3 3.5-2q1.8-1.1 3.5-2.3c1.2-0.8 2.2-1.9 3.5-2.4zm14.4-0.6c1-0.2 2 0.3 2.3 1.3 0.3 1 0 1.2 0.7 1.9 0.6 0.6 1.3 1.1 1.9 1.6l1 0.7c1.8 1.3 3.6 2.5 5.6 3.4 0.2 0.1 0.1 0.3-0.1 0.3-3.2 0.1-6.3-0.3-9.2-1.8-1.4-0.7-2.8-1.5-3.5-2.9-1-1.5-0.9-4.1 1.3-4.5z"/>
21
+ </g>
22
+ <g id="facial-hair/*-None">
23
+ </g>
24
+ <g id="accessories/*-None">
25
+ </g>
26
+ </g>
27
+ </g>
28
+ </g>
29
+ </g>
30
+ </svg>