Public Source Viewer

비나래아카이브 개발자 포털

실제 서비스 구조를 살펴볼 수 있는 공개용 코드 뷰어입니다. 인증, 세션, 외부 연동, 토큰, 관리자 식별 등 보안상 민감한 구현은 파일 단위 또는 줄 단위로 검열됩니다.

Redacted View
view/hinana/gallery.ejs
공개 가능
1 <!DOCTYPE html>
2 <html lang="ko" xmlns="http://www.w3.org/1999/xhtml">
3 <head>
4 <meta charset="utf-8" />
5 <meta name="color-scheme" content="light dark">
6 <meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no, maximum-scale=1.0">
7 <link rel="manifest" href="/manifest.json">
8 <meta name="theme-color" content="<%= (typeof theme !== 'undefined' && theme === 'dark') ? '#0f141e' : '#f8f7f5' %>">
9 <meta name="apple-mobile-web-app-title" content="비나래 라운지 갤러리">
10 <meta property="og:image" content="/image/lounge1.png" />
11 <meta property="og:description" content="비나래 라운지 갤러리"/>
12 <meta property="og:url" content="hinana.moe/hinana/gallery"/>
13 <meta property="og:title" content="비나래 라운지 갤러리"/>
14 <title>비나래 라운지 갤러리</title>
15
16 <link rel='stylesheet' href='/vendors/bootstrap/css/bootstrap.min.css' />
17 <script src="/vendors/bootstrap/js/bootstrap.min.js"></script>
18 <link href="https://fonts.googleapis.com/css?family=Montserrat:400,700" rel="stylesheet" type="text/css">
19 <link href="https://fonts.googleapis.com/css?family=Lato:300,400,700" rel="stylesheet" type="text/css">
20 <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons/font/bootstrap-icons.css">
21
22 <style>
23 :root {
24 --font-family: 'Noto Sans KR', sans-serif;
25 --bg-main: #f8f7f5; --bg-secondary: #ffffff; --bg-tertiary: #1a2238;
26 --text-primary: #1a2238; --text-secondary: #5e6676;
27 --accent-color: #c5a059; --border-color: #e5e1da;
28 --shadow-md: 0 10px 40px -10px rgba(26, 34, 56, 0.12);
29 --shadow-sm: 0 2px 8px rgba(0,0,0,0.05);
30 }
31
32 body.dark-mode {
33 --bg-main: #0f141e; --bg-secondary: #1a2238; --bg-tertiary: #0a0e17;
34 --text-primary: #e7e5e4; --text-secondary: #a8a29e;
35 --accent-color: #d4b47a; --border-color: #2e3a59;
36 }
37
38 html, body {
39 height: auto !important; min-height: 100%; margin: 0; padding: 0;
40 font-family: var(--font-family); background-color: var(--bg-main); color: var(--text-primary);
41 overflow-x: hidden; overflow-y: auto; width: 100%;
42 }
43 a { text-decoration: none; color: inherit; }
44
45 .global-header {
46 height: 60px; background-color: var(--bg-tertiary); border-bottom: 1px solid var(--border-color);
47 display: flex; align-items: center; justify-content: space-between; padding: 0 40px;
48 position: sticky; top: 0; z-index: 1000; color: white; flex-wrap: wrap;
49 }
50 .header-logo { height: 32px; filter: none !important; -webkit-filter: none !important; mix-blend-mode: normal !important; }
51 .header-brand { display: flex; align-items: center; flex: 0 0 auto; }
52 .header-nav { display: flex; gap: 20px; align-items: center; transition: all 0.3s ease; }
53
54 /* [Layout] */
55 .layout-container {
56 display: flex;
57 min-height: calc(100vh - 60px);
58 background-color: var(--bg-main);
59 width: 100%; max-width: 100vw; overflow-x: hidden;
60 }
61
62 .content-column {
63 flex: 1; padding: 60px 40px;
64 display: flex; flex-direction: column; align-items: center;
65 width: 100%; min-width: 0;
66 }
67
68 /* [Right Sidebar] */
69 .info-column {
70 flex: 0 0 320px;
71 width: 320px;
72 background-color: var(--bg-secondary);
73 border-left: 1px solid var(--border-color);
74 padding: 40px 0;
75 display: flex; flex-direction: column; align-items: center;
76 }
77
78 .info-card {
79 width: 270px;
80 background-color: var(--bg-main);
81 border: 1px solid var(--border-color);
82 border-radius: 12px;
83 padding: 24px 20px;
84 margin-bottom: 20px;
85 box-shadow: var(--shadow-sm);
86 }
87
88 .gallery-hero { text-align: center; margin-bottom: 50px; }
89 .gallery-title { font-size: 2.8rem; font-weight: 700; color: var(--text-primary); margin: 15px 0; letter-spacing: -1px; }
90
91 .gallery-section {
92 width: 100%; background-color: var(--bg-secondary);
93 padding: 40px; border-radius: 4px; border: 1px solid var(--border-color);
94 border-top: 5px solid var(--accent-color) !important; box-shadow: var(--shadow-md);
95 margin-bottom: 40px;
96 }
97
98 .section-label {
99 font-size: 0.65rem; color: var(--accent-color); letter-spacing: 3px;
100 font-weight: 700; text-transform: uppercase; margin-bottom: 10px;
101 }
102 .section-title {
103 font-size: 1.3rem; font-weight: 700; margin-bottom: 30px;
104 padding-bottom: 15px; border-bottom: 1px solid var(--border-color);
105 }
106
107 .color-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(180px, 1fr)); gap: 20px; }
108 .color-card {
109 border: 1px solid var(--border-color); border-radius: 8px; overflow: hidden;
110 background-color: var(--bg-main); transition: all 0.2s;
111 }
112 .color-card:hover { transform: translateY(-3px); box-shadow: var(--shadow-md); }
113 .color-swatch { height: 80px; width: 100%; }
114 .color-info { padding: 12px 14px; }
115 .color-name { font-weight: 700; font-size: 0.85rem; margin-bottom: 2px; }
116 .color-hex { font-size: 0.75rem; color: var(--text-secondary); font-family: 'Courier New', monospace; }
117
118 .logo-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); gap: 20px; }
119 .logo-card {
120 border: 1px solid var(--border-color); border-radius: 8px; overflow: hidden;
121 background-color: var(--bg-main); text-align: center; padding: 30px 20px;
122 transition: all 0.2s; cursor: pointer;
123 }
124 .logo-card:hover { transform: translateY(-3px); box-shadow: var(--shadow-md); border-color: var(--accent-color); }
125 .logo-card img { max-height: 48px; max-width: 100%; object-fit: contain; margin-bottom: 15px; }
126 .logo-label { font-weight: 700; font-size: 0.85rem; }
127
128 .gallery-modal .modal-content {
129 background-color: var(--bg-secondary); color: var(--text-primary);
130 border: 1px solid var(--border-color); border-radius: 8px;
131 border-top: 4px solid var(--accent-color);
132 }
133 .gallery-modal .modal-header { border-bottom: 1px solid var(--border-color); }
134 body.dark-mode .gallery-modal .btn-close { filter: invert(1); }
135 .gallery-modal .modal-body { padding: 25px 30px; }
136 .gallery-modal .service-item {
137 display: flex; align-items: center; gap: 15px;
138 padding: 16px; margin-bottom: 12px;
139 background-color: var(--bg-main); border: 1px solid var(--border-color);
140 border-radius: 8px; transition: all 0.2s; text-decoration: none; color: inherit;
141 }
142 .gallery-modal .service-item:hover {
143 border-color: var(--accent-color); transform: translateX(5px); box-shadow: var(--shadow-sm);
144 }
145 .gallery-modal .service-item:last-child { margin-bottom: 0; }
146 .gallery-modal .service-icon {
147 width: 40px; height: 40px; border-radius: 8px;
148 background-color: var(--bg-secondary); display: flex; align-items: center; justify-content: center;
149 font-size: 1.2rem; color: var(--accent-color); flex-shrink: 0;
150 }
151 .gallery-modal .service-name { font-weight: 700; font-size: 0.9rem; margin-bottom: 2px; }
152 .gallery-modal .service-desc { font-size: 0.75rem; color: var(--text-secondary); }
153
154 .footer-area {
155 text-align: center; padding: 40px 20px; margin-top: 20px;
156 font-size: 0.7rem; color: var(--text-secondary); line-height: 1.8;
157 }
158
159 @media (max-width: 1200px) {
160 .global-header { padding: 10px 20px; }
161 .layout-container { flex-direction: column; align-items: center; }
162 .content-column { width: 100%; padding: 40px 20px; }
163
164 .info-column {
165 width: 100%; flex: auto;
166 border-left: none; border-top: 1px solid var(--border-color);
167 padding: 40px 20px;
168 }
169 .info-card { width: 100%; }
170 .info-column > div:last-child { margin-bottom: 60px; }
171 }
172
173 @media (max-width: 991px) {
174 .global-header { height: auto; min-height: 60px; padding: 10px 15px; }
175 .header-brand { order: 1; }
176 .header-nav { gap: 15px !important; order: 2; margin-left: auto; }
177 .header-controls {
178 width: 100%; order: 3; display: flex; justify-content: flex-end;
179 margin-top: 10px; padding-top: 10px; border-top: 1px solid rgba(255,255,255,0.15);
180 }
181 }
182
183 @media (max-width: 768px) {
184 .content-column { padding: 30px 15px; }
185 .gallery-section { padding: 25px 18px; }
186 .gallery-title { font-size: 2rem; }
187 .color-grid { grid-template-columns: repeat(2, 1fr); gap: 12px; }
188 .logo-grid { grid-template-columns: repeat(2, 1fr); gap: 12px; }
189 }
190 </style>
191 </head>
192
193 <body class="<%= (typeof theme !== 'undefined' && theme === 'dark') ? 'dark-mode' : '' %>">
194 <header class="global-header">
195 <div class="header-brand">
196 <a href="/hinana/lounge">
197 <img src="/image/lounge1.png" alt="Logo" class="header-logo">
198 </a>
199 </div>
200 <nav class="header-nav">
201 <a href="/hinana/index" class="nav-link text-white-50 small fw-bold">Archive</a>
202 <a href="/hinana/lounge" class="nav-link text-white-50 small fw-bold">Lounge</a>
203 <a href="/hinana/gallery" class="nav-link text-white fw-bold">Gallery</a>
204 </nav>
205 <div class="header-controls" style="display:flex; align-items:center; gap:12px;">
206 <a href="#brand-assets" class="text-white-50 small fw-bold" style="text-decoration:none;">사이트 맵</a>
207 <form action="/toggle-theme" method="POST" style="margin:0;">
208 <button type="submit" class="btn text-white p-1"><i class="bi bi-moon-stars"></i></button>
209 </form>
210 </div>
211 </header>
212
213 <div class="layout-container">
214 <div class="content-column">
215
216 <div class="gallery-hero">
217 <span style="color: var(--accent-color); letter-spacing: 5px; font-weight: bold; font-size: 0.8rem;">LOUNGE GALLERY</span>
218 <h2 class="gallery-title">라운지 갤러리</h2>
219 <div style="width: 60px; height: 1px; background: var(--accent-color); margin: 0 auto;"></div>
220 <p class="text-secondary mt-3">비나래아카이브와 비나래 라운지의 디자인 및 서비스들을 소개합니다.</p>
221 </div>
222
223 <!-- 색상 팔레트 섹션 -->
224 <div class="gallery-section">
225 <div class="section-label">COLOR PALETTE</div>
226 <div class="section-title">비나래아카이브와 비나래 라운지에는 이런 색들이 사용되었어요.</div>
227
228 <div class="color-grid">
229 <div class="color-card">
230 <div class="color-swatch" style="background-color: #FFC639;"></div>
231 <div class="color-info">
232 <div class="color-name">히나나 옐로우</div>
233 <div class="color-hex">#FFC639</div>
234 </div>
235 </div>
236 <div class="color-card">
237 <div class="color-swatch" style="background-color: #1a2238;"></div>
238 <div class="color-info">
239 <div class="color-name">비나래 다크 블루</div>
240 <div class="color-hex">#1a2238</div>
241 </div>
242 </div>
243 <div class="color-card">
244 <div class="color-swatch" style="background-color: #b45309;"></div>
245 <div class="color-info">
246 <div class="color-name">비나래 아카이브 브라운</div>
247 <div class="color-hex">#b45309</div>
248 </div>
249 </div>
250 <div class="color-card">
251 <div class="color-swatch" style="background-color: #c5a059;"></div>
252 <div class="color-info">
253 <div class="color-name">비나래 라운지 골드</div>
254 <div class="color-hex">#c5a059</div>
255 </div>
256 </div>
257 <div class="color-card">
258 <div class="color-swatch" style="background-color: #e4dfd7;"></div>
259 <div class="color-info">
260 <div class="color-name">비나래 아카이브 베이지</div>
261 <div class="color-hex">#e4dfd7</div>
262 </div>
263 </div>
264 <div class="color-card">
265 <div class="color-swatch" style="background-color: #f8f7f5;"></div>
266 <div class="color-info">
267 <div class="color-name">비나래 라운지 아이보리</div>
268 <div class="color-hex">#f8f7f5</div>
269 </div>
270 </div>
271 <div class="color-card">
272 <div class="color-swatch" style="background-color: #0f141e;"></div>
273 <div class="color-info">
274 <div class="color-name">비나래 다크모드 블랙</div>
275 <div class="color-hex">#0f141e</div>
276 </div>
277 </div>
278 <div class="color-card">
279 <div class="color-swatch" style="background-color: #1c1917;"></div>
280 <div class="color-info">
281 <div class="color-name">비나래 아카이브 다크</div>
282 <div class="color-hex">#1c1917</div>
283 </div>
284 </div>
285 <div class="color-card">
286 <div class="color-swatch" style="background-color: #f2f0eb;"></div>
287 <div class="color-info">
288 <div class="color-name">비나래 아카이브 크림</div>
289 <div class="color-hex">#f2f0eb</div>
290 </div>
291 </div>
292 <div class="color-card">
293 <div class="color-swatch" style="background-color: #3e3a36;"></div>
294 <div class="color-info">
295 <div class="color-name">비나래 아카이브 차콜</div>
296 <div class="color-hex">#3e3a36</div>
297 </div>
298 </div>
299 <div class="color-card">
300 <div class="color-swatch" style="background-color: #f59e0b;"></div>
301 <div class="color-info">
302 <div class="color-name">비나래 아카이브 다크모드 앰버</div>
303 <div class="color-hex">#f59e0b</div>
304 </div>
305 </div>
306 <div class="color-card">
307 <div class="color-swatch" style="background-color: #d4b47a;"></div>
308 <div class="color-info">
309 <div class="color-name">비나래 라운지 다크모드 골드</div>
310 <div class="color-hex">#d4b47a</div>
311 </div>
312 </div>
313 <div class="color-card">
314 <div class="color-swatch" style="background-color: #0a0e17;"></div>
315 <div class="color-info">
316 <div class="color-name">특급 히나나호 나이트</div>
317 <div class="color-hex">#0a0e17</div>
318 </div>
319 </div>
320 <div class="color-card">
321 <div class="color-swatch" style="background-color: #1d9bf0;"></div>
322 <div class="color-info">
323 <div class="color-name">비나래 체크마크 블루</div>
324 <div class="color-hex">#1d9bf0</div>
325 </div>
326 </div>
327 <div class="color-card">
328 <div class="color-swatch" style="background-color: #dc2626;"></div>
329 <div class="color-info">
330 <div class="color-name">비나래 레드</div>
331 <div class="color-hex">#dc2626</div>
332 </div>
333 </div>
334 </div>
335 </div>
336
337 <!-- 로고/서비스 섹션 -->
338 <div class="gallery-section" id="brand-assets">
339 <div class="section-label">BRAND ASSETS</div>
340 <div class="section-title">현재 이런 서비스들을 제공하고 있죠.<span style="font-size:0.7em;">(터치 및 클릭시 팝업)</span></div>
341
342 <div class="logo-grid">
343 <div class="logo-card" data-bs-toggle="modal" data-bs-target="#archiveModal">
344 <img src="/image/<%= (typeof theme !== 'undefined' && theme === 'dark') ? 'archive1.png' : 'archive.png' %>" alt="비나래아카이브">
345 <div class="logo-label">비나래아카이브</div>
346 </div>
347 <div class="logo-card" data-bs-toggle="modal" data-bs-target="#libraryModal">
348 <img src="/image/<%= (typeof theme !== 'undefined' && theme === 'dark') ? 'library1.png' : 'library.png' %>" alt="비나래아카이브 도서관">
349 <div class="logo-label">비나래아카이브 도서관</div>
350 </div>
351 <div class="logo-card" data-bs-toggle="modal" data-bs-target="#loungeModal">
352 <img src="/image/<%= (typeof theme !== 'undefined' && theme === 'dark') ? 'lounge1.png' : 'lounge.png' %>" alt="비나래 라운지">
353 <div class="logo-label">비나래 라운지</div>
354 </div>
355 <div class="logo-card" data-bs-toggle="modal" data-bs-target="#railwayModal">
356 <img src="/image/<%= (typeof theme !== 'undefined' && theme === 'dark') ? 'train1.png' : 'train.png' %>" alt="비나래아카이브 철도국">
357 <div class="logo-label">비나래아카이브 철도국</div>
358 </div>
359 </div>
360 </div>
361
362 </div>
363
364 <div class="info-column">
365 <div class="info-card text-center">
366 <div style="font-size: 0.65rem; color: var(--accent-color); letter-spacing: 3px; font-weight: 700; margin-bottom: 20px;">PASSENGER INFO</div>
367 [SECURITY REDACTED] 민감한 설정/인증/토큰 관련 코드입니다.
368 <div>
369 <% if(username) { %>
370 <a href="/logout?redirect=/hinana/gallery" class="btn btn-outline-dark btn-sm w-100 py-2" style="letter-spacing: 1px;">SIGN OUT</a>
371 <% } else { %>
372 <a href="/login?redirect=/hinana/gallery" class="btn btn-dark btn-sm w-100 py-2" style="letter-spacing: 1px;">SIGN IN</a>
373 <% } %>
374 </div>
375 </div>
376
377 [SECURITY REDACTED] 민감한 설정/인증/토큰 관련 코드입니다.
378 <div class="info-card border-warning shadow-sm">
379 <div class="small fw-bold text-warning mb-3"><i class="bi bi-gear-wide-connected me-2"></i> ADMINISTRATION</div>
380 <a href="/hinana/admin" class="d-flex justify-content-between align-items-center text-decoration-none" style="color: inherit;">
381 <span class="small"><i class="bi bi-bookmark-star-fill me-1"></i> 책갈피 관리</span>
382 <i class="bi bi-chevron-right text-secondary"></i>
383 </a>
384 </div>
385 <% } %>
386
387 <div class="info-card">
388 <div style="font-size: 0.65rem; color: var(--accent-color); letter-spacing: 3px; font-weight: 700; margin-bottom: 15px;">SYSTEM INFO</div>
389 <ul class="small text-secondary list-unstyled mb-0" style="font-size: 0.75rem;">
390 <li class="mb-1 d-flex justify-content-between">
391 <span>Version</span>
392 <span class="text-end">Ver. 6.5.4.0-Kozeki Ui</span>
393 </li>
394 </ul>
395 </div>
396
397 <div class="mt-auto text-center pt-5">
398 <img src="/image/sign.png" style="width: 160px; opacity: 0.7; mix-blend-mode: multiply;">
399 <div class="mt-4 pt-4 border-top" style="font-size: 0.7rem; color: var(--text-secondary); line-height: 1.8;">
400 <strong>비나래 라운지</strong><br>
401 X - @NoctchillHinana<br>
402 ⓒ 2024~2026. 비나래 | hinana.moe
403 </div>
404 </div>
405 </div>
406 </div>
407
408 <!-- 비나래아카이브 모달 -->
409 <div class="modal fade gallery-modal" id="archiveModal" tabindex="-1">
410 <div class="modal-dialog modal-dialog-centered">
411 <div class="modal-content">
412 <div class="modal-header">
413 <h6 class="modal-title fw-bold">비나래아카이브</h6>
414 <button type="button" class="btn-close" data-bs-dismiss="modal"></button>
415 </div>
416 <div class="modal-body">
417 <a href="/" class="service-item">
418 <div class="service-icon"><i class="bi bi-house-door"></i></div>
419 <div>
420 <div class="service-name">메인 화면</div>
421 <div class="service-desc">hinana.moe의 첫 번째 페이지. 비나래아카이브의 시작점이에요.</div>
422 </div>
423 </a>
424 <a href="/hinana/index" class="service-item">
425 <div class="service-icon"><i class="bi bi-archive"></i></div>
426 <div>
427 <div class="service-name">비나래아카이브</div>
428 <div class="service-desc">비나래씨의 SNS이자 모두의 SNS. 일상과 생각을 기록하는 아카이브 공간이에요.</div>
429 </div>
430 </a>
431 <a href="/hinana/info" class="service-item">
432 <div class="service-icon"><i class="bi bi-person-circle"></i></div>
433 <div>
434 <div class="service-name">비나래씨란?</div>
435 <div class="service-desc">비나래씨에 대해 알아볼 수 있는 소개 페이지예요.</div>
436 </div>
437 </a>
438 [SECURITY REDACTED] 민감한 설정/인증/토큰 관련 코드입니다.
439 <a href="/hinana/personal-notes" class="service-item">
440 <div class="service-icon"><i class="bi bi-journal"></i></div>
441 <div>
442 <div class="service-name">개인 노트</div>
443 <div class="service-desc">비나래씨만 사용하는 개인 노트 공간이에요.</div>
444 </div>
445 </a>
446 <% } %>
447 </div>
448 </div>
449 </div>
450 </div>
451
452 <!-- 비나래아카이브 도서관 모달 -->
453 <div class="modal fade gallery-modal" id="libraryModal" tabindex="-1">
454 <div class="modal-dialog modal-dialog-centered">
455 <div class="modal-content">
456 <div class="modal-header">
457 <h6 class="modal-title fw-bold">비나래아카이브 도서관</h6>
458 <button type="button" class="btn-close" data-bs-dismiss="modal"></button>
459 </div>
460 <div class="modal-body">
461 <a href="/hinana/blog" class="service-item">
462 <div class="service-icon"><i class="bi bi-book"></i></div>
463 <div>
464 <div class="service-name">비나래아카이브 도서관</div>
465 <div class="service-desc">비나래씨의 블로그. 긴 글과 이야기를 담아두는 도서관이에요.</div>
466 </div>
467 </a>
468 </div>
469 </div>
470 </div>
471 </div>
472
473 <!-- 비나래 라운지 모달 -->
474 <div class="modal fade gallery-modal" id="loungeModal" tabindex="-1">
475 <div class="modal-dialog modal-dialog-centered">
476 <div class="modal-content">
477 <div class="modal-header">
478 <h6 class="modal-title fw-bold">비나래 라운지</h6>
479 <button type="button" class="btn-close" data-bs-dismiss="modal"></button>
480 </div>
481 <div class="modal-body">
482 <a href="/hinana/lounge" class="service-item">
483 <div class="service-icon"><i class="bi bi-cup-hot"></i></div>
484 <div>
485 <div class="service-name">비나래 라운지</div>
486 <div class="service-desc">아카이브를 나와 라운지로. 다양한 기능들의 허브예요.</div>
487 </div>
488 </a>
489 <a href="/hinana/plaza" class="service-item">
490 <div class="service-icon"><i class="bi bi-chat-dots"></i></div>
491 <div>
492 <div class="service-name">비나래 광장</div>
493 <div class="service-desc">24시간 동안 유지되는 실시간 광장. 자유롭게 이야기해요.</div>
494 </div>
495 </a>
496 <a href="/hinana/gallery" class="service-item">
497 <div class="service-icon"><i class="bi bi-palette"></i></div>
498 <div>
499 <div class="service-name">라운지 갤러리</div>
500 <div class="service-desc">비나래씨의 디자인과 서비스들을 전시하는 갤러리예요.</div>
501 </div>
502 </a>
503 <a href="/hinana/tetris" class="service-item">
504 <div class="service-icon"><i class="bi bi-controller"></i></div>
505 <div>
506 <div class="service-name">TETRIS</div>
507 <div class="service-desc">라운지에서 즐기는 테트리스 게임이에요.</div>
508 </div>
509 </a>
510 <a href="/hinana/shop" class="service-item">
511 <div class="service-icon"><i class="bi bi-bookmark-star"></i></div>
512 <div>
513 <div class="service-name">책갈피 교환소</div>
514 <div class="service-desc">책갈피로 다양한 커스텀 아이템을 구매할 수 있어요.</div>
515 </div>
516 </a>
517 <a href="/hinana/image" class="service-item">
518 <div class="service-icon"><i class="bi bi-image"></i></div>
519 <div>
520 <div class="service-name">이미지 편집기</div>
521 <div class="service-desc">이미지를 불러와 원하는 위치에 텍스트를 추가하고 저장할 수 있어요.</div>
522 </div>
523 </a>
524 <a href="/hinana/exhibition" class="service-item">
525 <div class="service-icon"><i class="bi bi-easel2"></i></div>
526 <div>
527 <div class="service-name">특별전 <span style="font-size:0.7em; opacity:0.6;">Claude Design 테스트</span></div>
528 <div class="service-desc">Claude Design으로 제작한 미술관 스타일의 갤러리 특별전시입니다.</div>
529 </div>
530 </a>
531 <a href="/hinana/echo" class="service-item">
532 <div class="service-icon"><i class="bi bi-soundwave"></i></div>
533 <div>
534 <div class="service-name">에코 스튜디오</div>
535 <div class="service-desc">음악 파일에 노래방 스타일 에코 효과를 입혀 저장할 수 있어요.</div>
536 </div>
537 </a>
538 [SECURITY REDACTED] 민감한 설정/인증/토큰 관련 코드입니다.
539 <div class="service-icon"><i class="bi bi-calculator"></i></div>
540 <div>
541 <div class="service-name">AI 토큰 계산기</div>
542 <div class="service-desc">GPT-5.5 기준으로 텍스트의 토큰 수와 예상 비용을 계산합니다.</div>
543 </div>
544 </a>
545 <a href="/hinana/subway" class="service-item">
546 <div class="service-icon"><i class="bi bi-train-front"></i></div>
547 <div>
548 <div class="service-name">열차 위치 조회</div>
549 <div class="service-desc">서울시 지하철 API로 열번의 현재 위치와 진입·도착·출발 상태를 확인합니다.</div>
550 </div>
551 </a>
552 </div>
553 </div>
554 </div>
555 </div>
556
557 <!-- 비나래아카이브 철도국 모달 -->
558 <div class="modal fade gallery-modal" id="railwayModal" tabindex="-1">
559 <div class="modal-dialog modal-dialog-centered">
560 <div class="modal-content">
561 <div class="modal-header">
562 <h6 class="modal-title fw-bold">비나래아카이브 철도국</h6>
563 <button type="button" class="btn-close" data-bs-dismiss="modal"></button>
564 </div>
565 <div class="modal-body">
566 <a href="/hinana/train" class="service-item">
567 <div class="service-icon"><i class="bi bi-train-front"></i></div>
568 <div>
569 <div class="service-name">특급 히나나호</div>
570 <div class="service-desc">비내리는 열차를 탑승하여 기차 소리를 들으며 여행해보세요.</div>
571 </div>
572 </a>
573 <a href="/hinana/kivotosExp" class="service-item">
574 <div class="service-icon"><i class="bi bi-train-lightrail-front"></i></div>
575 <div>
576 <div class="service-name">키보토스 광역급행철도</div>
577 <div class="service-desc">플랫폼에서 승객을 만나고 노조미 또는 히카리 특급을 탑승해보세요.</div>
578 </div>
579 </a>
580 <a href="/hinana/lcd" class="service-item">
581 <div class="service-icon"><i class="bi bi-display"></i></div>
582 <div>
583 <div class="service-name">키보토스광역급행철도 LCD</div>
584 <div class="service-desc">키보토스 광역급행철도 열차 내 LCD 안내판을 재현합니다.</div>
585 </div>
586 </a>
587 </div>
588 </div>
589 </div>
590 </div>
591
592 <script>if ("serviceWorker" in navigator) { navigator.serviceWorker.register("/sw.js"); }</script>
593 </body>
594 </html>
595