diff --git a/.vitepress/theme/components/HomeLanding.vue b/.vitepress/theme/components/HomeLanding.vue index c3a4bcb3e..39e355711 100644 --- a/.vitepress/theme/components/HomeLanding.vue +++ b/.vitepress/theme/components/HomeLanding.vue @@ -1,270 +1,463 @@ @@ -295,6 +488,7 @@ const platforms = [ /* hero */ .hero { + position: relative; display: grid; grid-template-columns: 1fr; gap: 0; @@ -317,7 +511,7 @@ const platforms = [ .hero-figure img { display: block; - width: 240px; + height: 300px; animation: sway 6s ease-in-out infinite; transform-origin: 50% 100%; } @@ -326,19 +520,11 @@ const platforms = [ padding: 28px 24px 32px; } -.kicker { - margin: 0 0 12px; - font-family: var(--clice-font-display); - font-weight: 900; - font-size: 14px; - letter-spacing: 0.04em; - color: var(--bow); -} - +/* She says the whole introduction: one balloon holds the headline and the + lead, filling the column so its edge (and the tail's root) sits by her. */ .bubble { position: relative; - display: inline-block; - padding: 14px 22px; + padding: 20px 24px 22px; border: var(--line) solid var(--line-color); border-radius: 18px; background: var(--paper); @@ -349,26 +535,29 @@ const platforms = [ background: var(--paper); } -.bubble::before, -.bubble::after { - content: ''; +.tail { position: absolute; - top: 22px; - left: -14px; - border-style: solid; - border-width: 0 14px 12px 0; - border-color: transparent var(--line-color) transparent transparent; + inset: 0; + width: 100%; + height: 100%; + pointer-events: none; + animation: fade-in 0.2s ease 0.5s both; } -.bubble::after { - left: -9px; - top: 24px; - border-width: 0 10px 8px 0; - border-color: transparent var(--paper) transparent transparent; +.tail-fill { + fill: var(--paper); +} + +.tail-line { + fill: none; + stroke: var(--line-color); + stroke-width: var(--line); + stroke-linejoin: round; } .bubble h1 { margin: 0; + text-wrap: balance; font-family: var(--clice-font-display); font-weight: 900; font-size: 30px; @@ -377,8 +566,7 @@ const platforms = [ } .lead { - margin: 20px 0 0; - max-width: 560px; + margin: 12px 0 0; font-size: 16px; line-height: 1.7; color: var(--ink-2); @@ -392,7 +580,9 @@ const platforms = [ } .btn { - display: inline-block; + display: inline-flex; + align-items: center; + gap: 8px; padding: 8px 22px; border: var(--line) solid var(--line-color); border-radius: 999px; @@ -425,93 +615,51 @@ const platforms = [ color: #1d212d; } -.btn.alt { - background: var(--straw); - color: #2b3040; -} - +/* Side by side the copy leads on the left and she stands on the right, so + she doesn't sit directly under the navbar logo. */ @media (min-width: 768px) { .hero { - grid-template-columns: 340px 1fr; + grid-template-columns: 1fr 340px; } .hero-figure { + order: 2; border-bottom: none; - border-right: var(--line) solid var(--line-color); + border-left: var(--line) solid var(--line-color); padding: 32px 24px 0; } .hero-figure img { - width: 280px; + height: 460px; } .hero-copy { - padding: 40px 40px 44px; display: flex; flex-direction: column; justify-content: center; + padding: 40px 40px 44px; } .bubble h1 { - font-size: 38px; + font-size: 32px; } } -/* works with / runs on */ - -.support { - margin-top: 26px; - padding-top: 18px; - border-top: var(--line-thin) dashed var(--line-color); - display: flex; - flex-direction: column; - gap: 10px; -} - -.support-row { - display: flex; - flex-wrap: wrap; - align-items: center; - gap: 8px; -} - -.support-label { - min-width: 78px; - font-family: var(--clice-font-display); - font-weight: 900; - font-size: 12px; - letter-spacing: 0.04em; - color: var(--ink-3); -} - -.chip { - display: inline-flex; - align-items: center; - gap: 6px; - padding: 0 10px; - border: var(--line-thin) solid var(--line-color); - border-radius: 999px; - background: var(--paper); - font-size: 12px; - font-weight: 700; - line-height: 24px; - color: var(--ink); - text-decoration: none; -} - -.chip.arch { - background: var(--straw-soft); -} +@media (min-width: 960px) { + .bubble { + padding: 26px 32px 28px; + } -.chip.link:hover { - border-color: var(--bow); - color: var(--bow); + .bubble h1 { + font-size: 38px; + } } /* section titles */ .section-title { position: relative; + scroll-margin-top: calc(var(--vp-nav-height) + 24px); margin: 56px 0 20px; padding: 4px 0 4px 16px; font-family: var(--clice-font-display); @@ -532,341 +680,358 @@ const platforms = [ box-sizing: border-box; } -/* projects */ +/* projects: one manga page, a panel per project */ -.projects { +.manga-page { + position: relative; display: grid; - grid-template-columns: 1fr; - gap: 20px; + grid-template-columns: minmax(0, 1fr); + gap: 40px; } -@media (min-width: 768px) { - .projects { - grid-template-columns: repeat(3, minmax(0, 1fr)); +@media (min-width: 960px) { + .manga-page { + grid-template-columns: minmax(0, 5fr) minmax(0, 7fr); + grid-template-areas: + 'catter clice' + 'kotatsu kotatsu'; + gap: 34px 38px; + } + + .panel.catter { + grid-area: catter; + } + + .panel.clice { + grid-area: clice; + } + + .panel.kotatsu { + grid-area: kotatsu; } } -.project { - position: relative; - display: flex; - flex-direction: column; - padding: 22px 22px 26px; - text-decoration: none; - color: inherit; - overflow: hidden; - transition: - transform 0.12s ease, - box-shadow 0.12s ease; +/* Panel order follows the story: the build, then clice, then what holds + them up. */ +.panel.catter { + order: 1; } -.project::before { - content: ''; - position: absolute; - inset: 0 auto 0 0; - width: 10px; - border-right: var(--line) solid var(--line-color); - background: var(--accent); +.panel.clice { + order: 2; } -.project.bow { - --accent: var(--bow); +.panel.kotatsu { + order: 3; } -.project.aqua { - --accent: var(--aqua); +.page-frames, +.page-arrows { + position: absolute; + inset: 0; + width: 100%; + height: 100%; + overflow: visible; + pointer-events: none; } -.project.straw { - --accent: var(--straw); +.page-frames path { + fill: var(--panel); + stroke: var(--line-color); + stroke-width: 2.5; + stroke-linejoin: round; } -.project:hover { - transform: translate(-2px, -2px); - box-shadow: 6px 6px 0 var(--shadow-color); +.dark .page-frames path { + fill: var(--paper-2); } -.project .art { - margin: -22px -22px 16px -22px; - padding-left: 10px; - height: 170px; - border-bottom: var(--line) solid var(--line-color); - background: - var(--screentone) 0 0 / 10px 10px, - #ffffff; - display: flex; - justify-content: center; - align-items: flex-end; - overflow: hidden; +.page-arrows { + z-index: 2; } -.project .art img { - display: block; - height: 150px; - width: auto; - transition: transform 0.15s ease; +.page-arrows .halo { + fill: var(--panel); + stroke: var(--panel); + stroke-width: 9; + stroke-linejoin: round; + stroke-linecap: round; } -.project:hover .art img { - transform: translateY(-4px); +.dark .page-arrows .halo { + fill: var(--paper-2); + stroke: var(--paper-2); } -.project-head { - display: flex; - flex-wrap: wrap; - align-items: center; - gap: 8px 10px; - margin-left: 8px; +.page-arrows .shaft { + fill: none; + stroke: var(--ink); + stroke-width: 3; + stroke-linecap: round; } -.project h3 { - margin: 0; - font-family: var(--clice-font-display); - font-weight: 900; - font-size: 24px; - color: var(--ink); +.page-arrows .head { + fill: var(--ink); + stroke: var(--ink); + stroke-width: 1.5; + stroke-linejoin: round; } -.tag { - padding: 0 10px; +/* What one project hands to the next, pinned to the arrow between them. */ +.arrow-label { + position: absolute; + z-index: 3; + padding: 1px 8px; border: var(--line-thin) solid var(--line-color); - border-radius: 999px; - background: var(--straw-soft); - font-size: 12px; + border-radius: 4px; + background: var(--panel); + font-family: var(--vp-font-family-mono); font-weight: 700; - line-height: 20px; + font-size: 11px; + line-height: 18px; color: var(--ink); white-space: nowrap; + transform: translate(-50%, -50%) rotate(-3deg); } -.project p { - margin: 12px 0 0 8px; - font-size: 14px; - line-height: 1.65; - color: var(--ink-2); - flex-grow: 1; +.dark .arrow-label { + background: var(--paper-2); } -.arrow { - position: absolute; - right: 16px; - bottom: 10px; - font-family: var(--clice-font-display); - font-weight: 900; - font-size: 20px; - color: var(--bow); - transition: transform 0.12s ease; +.panel { + position: relative; + z-index: 1; + padding: 20px 22px 18px; } -.project:hover .arrow { - transform: translateX(4px); +/* Until the frames are measured (and without JS) a plain border stands in. */ +.manga-page:not(.framed) .panel { + border: var(--line) solid var(--line-color); + border-radius: var(--radius); + background: var(--panel); } -/* q&a comic */ +.dark .manga-page:not(.framed) .panel { + background: var(--paper-2); +} -.qa { - display: flex; - flex-direction: column; - gap: 28px; +.bow { + --accent: var(--bow); } -.qa-row { - display: grid; - grid-template-columns: 1fr; - grid-template-areas: - 'caption' - 'face' - 'answer'; - gap: 14px; +.aqua { + --accent: var(--aqua); } -.caption { - grid-area: caption; - display: flex; - align-items: center; - gap: 12px; - padding: 10px 16px; - border: var(--line) solid var(--line-color); - border-radius: 2px; - background: var(--paper-3); - box-shadow: var(--hard-shadow-sm); +.straw { + --accent: var(--straw); +} + +/* A narration box, square-cornered, in the top corner of the panel. */ +.narration { width: fit-content; max-width: 100%; + margin: 0 0 16px; + padding: 6px 12px; + border: var(--line-thin) solid var(--line-color); + border-left: 6px solid var(--accent); + background: var(--paper); + font-size: 13px; + line-height: 1.55; + color: var(--ink); } -.caption .q { - flex: 0 0 auto; - width: 26px; - height: 26px; - border: var(--line) solid var(--line-color); - border-radius: 999px; - background: var(--ribbon); - font-family: var(--clice-font-display); - font-weight: 900; - font-size: 13px; - line-height: 22px; - text-align: center; - color: #ffffff; - transform: rotate(-8deg); +.panel-main { + display: flex; + align-items: flex-start; + gap: 20px; } -.caption p { - margin: 0; - font-family: var(--clice-font-display); - font-weight: 700; - font-size: 15px; - color: var(--ink); +/* catter faces clice across the gutter, so its portrait sits on the right. */ +.panel.catter .panel-main { + flex-direction: row-reverse; } -.qa-row .face { - grid-area: face; - position: relative; - width: 160px; - height: 160px; - overflow: hidden; - background: #ffffff; +.panel-body { + flex: 1; + min-width: 0; } -.qa-row .face img { +.line-icon { display: block; - width: 100%; - height: 100%; - object-fit: cover; - object-position: center 20%; + fill: none; + stroke: var(--ink); + stroke-width: 2; + stroke-linecap: round; + stroke-linejoin: round; } -.num { - position: absolute; - left: 0; - top: 0; - width: 26px; - height: 26px; - border-right: var(--line) solid var(--line-color); - border-bottom: var(--line) solid var(--line-color); - border-radius: 0 0 var(--radius) 0; - background: var(--straw); - font-family: var(--clice-font-display); - font-weight: 900; - font-size: 13px; - line-height: 26px; - text-align: center; - color: #2b3040; +.line-icon :deep(.dot) { + fill: var(--ink); + stroke: none; } -.answer { - grid-area: answer; +/* A character's portrait frame; it tilts a little under the pointer. */ +.portrait { position: relative; - padding: 18px 22px 20px; + flex-shrink: 0; + display: grid; + place-items: center; + width: 68px; + height: 68px; border: var(--line) solid var(--line-color); - border-radius: 18px; - background: var(--panel); - box-shadow: var(--hard-shadow); -} - -.dark .answer { - background: var(--paper-2); + border-radius: 50%; + background: var(--paper); + box-shadow: 3px 3px 0 var(--accent); + transition: transform 0.15s ease; } -.answer::before, -.answer::after { - content: ''; - position: absolute; - top: -14px; - left: 28px; - border-style: solid; - border-width: 0 0 14px 14px; - border-color: transparent transparent var(--line-color) transparent; +.portrait .line-icon { + width: 34px; + height: 34px; } -.answer::after { - top: -9px; - left: 30px; - border-width: 0 0 10px 10px; - border-color: transparent transparent var(--panel) transparent; +.lit .portrait { + transform: rotate(-6deg); } -.dark .answer::after { - border-bottom-color: var(--paper-2); +.project-head { + display: flex; + flex-wrap: wrap; + align-items: center; + gap: 6px 10px; } -.answer h3 { - margin: 0 0 8px; +.panel h3 { + margin: 0; font-family: var(--clice-font-display); font-weight: 900; - font-size: 20px; + font-size: 28px; + line-height: 1.2; +} + +.panel h3 a { color: var(--ink); + text-decoration: none; } -.answer p { - margin: 0; +/* The title link covers the whole panel. */ +.stretch::after { + content: ''; + position: absolute; + inset: 0; +} + +.tag { + padding: 0 10px; + border: var(--line-thin) solid var(--line-color); + border-radius: 999px; + background: var(--straw-soft); + font-size: 12px; + font-weight: 700; + line-height: 20px; + color: var(--ink); + white-space: nowrap; +} + +.summary { + margin: 12px 0 0; font-size: 14px; - line-height: 1.7; + line-height: 1.65; color: var(--ink-2); } -.answer p + p { - margin-top: 8px; +/* The whole panel is the link; this only says where it goes. */ +.more { + display: inline-block; + margin-top: 12px; + font-family: var(--clice-font-display); + font-weight: 900; + font-size: 13px; + color: var(--bow); + transition: transform 0.12s ease; } -@media (min-width: 768px) { - .qa-row { - grid-template-columns: 160px 1fr; +.lit .more { + transform: translateX(4px); +} + +/* kotatsu's panel runs the full width: its name on the left, the + description beside it. */ +@media (min-width: 960px) { + .panel.kotatsu .panel-body { + display: grid; + grid-template-columns: minmax(0, 2fr) minmax(0, 3fr); grid-template-areas: - '. caption' - 'face answer'; - column-gap: 28px; - row-gap: 12px; - align-items: start; + 'head summary' + 'head more'; + column-gap: 32px; } - .qa-row.flip { - grid-template-columns: 1fr 160px; - grid-template-areas: - 'caption .' - 'answer face'; + .panel.kotatsu .project-head { + grid-area: head; + align-self: center; } - .qa-row.flip .caption { - justify-self: end; + .panel.kotatsu .summary, + .panel.kotatsu .more { + padding-left: 28px; + border-left: var(--line-thin) dashed var(--line-color); } - .answer::before, - .answer::after { - top: 26px; - left: -14px; - border-width: 0 14px 12px 0; - border-color: transparent var(--line-color) transparent transparent; + .panel.kotatsu .summary { + grid-area: summary; + margin: 0; + align-self: end; } - .answer::after { - top: 28px; - left: -9px; - border-width: 0 10px 8px 0; - border-color: transparent var(--panel) transparent transparent; + .panel.kotatsu .more { + grid-area: more; + justify-self: start; + margin: 0; + padding-top: 12px; } +} - .dark .answer::after { - border-right-color: var(--paper-2); - border-bottom-color: transparent; +/* Narrow screens: the portrait sits beside the name only, and everything + below uses the panel's full width. */ +@media (max-width: 639px) { + .panel-main { + display: grid; + grid-template-columns: auto minmax(0, 1fr); + gap: 0 14px; } - .qa-row.flip .answer::before, - .qa-row.flip .answer::after { - left: auto; - right: -14px; - border-width: 12px 0 0 14px; - border-color: transparent transparent transparent var(--line-color); + .panel.catter .panel-main { + grid-template-columns: minmax(0, 1fr) auto; } - .qa-row.flip .answer::after { - right: -9px; - top: 28px; - border-width: 8px 0 0 10px; - border-color: transparent transparent transparent var(--panel); + .panel.catter .portrait { + grid-column: 2; + grid-row: 1; } - .dark .qa-row.flip .answer::after { - border-left-color: var(--paper-2); - border-right-color: transparent; + .panel-body { + display: contents; + } + + .project-head { + align-self: center; + } + + .summary, + .more { + grid-column: 1 / -1; + } + + .portrait { + width: 56px; + height: 56px; + } + + .portrait .line-icon { + width: 28px; + height: 28px; } } @@ -896,6 +1061,12 @@ const platforms = [ } } +@keyframes fade-in { + from { + opacity: 0; + } +} + @keyframes sway { 0%, 100% { @@ -910,6 +1081,7 @@ const platforms = [ @media (prefers-reduced-motion: reduce) { .hero, .bubble, + .tail, .hero-figure img { animation: none; } diff --git a/.vitepress/theme/components/SiteFooter.vue b/.vitepress/theme/components/SiteFooter.vue index 50a073dd9..c3fe4d17a 100644 --- a/.vitepress/theme/components/SiteFooter.vue +++ b/.vitepress/theme/components/SiteFooter.vue @@ -46,7 +46,7 @@ const other = computed(() => (zh.value ? { text: 'English', href: '/' } : { text