diff --git a/backend/static/logo.svg b/backend/static/logo.svg new file mode 100644 index 0000000..8571fba --- /dev/null +++ b/backend/static/logo.svg @@ -0,0 +1,23 @@ + diff --git a/backend/static/style.css b/backend/static/style.css index ec5b736..c1e8ce7 100644 --- a/backend/static/style.css +++ b/backend/static/style.css @@ -81,6 +81,11 @@ --danger-ink: #150808; --danger-soft: #e2aaa1; --brass: #b8912f; /* favourite — a second, cooler metal */ + /* One accent per action, so a press says which lane it belongs to. All three + are held at the same weight as --brass: muted, no ember competition. */ + --slate: #7fa0c0; /* archive */ + --moss: #7fae86; /* finished */ + --clay: #b5906f; /* set chapter */ --trash: #977671; /* remove, resting — icons need 3:1, not 4.5:1 */ /* Desktop cell borders for the two coloured action states. */ @@ -98,7 +103,7 @@ --measure: 760px; /* Cover width + row gap: the disclosure panels indent past the cover on desktop, so both live here rather than as magic numbers. */ - --cover-w: 86px; + --cover-w: 93px; --row-gap: 14px; } @@ -131,6 +136,9 @@ --danger-ink: #fff; --danger-soft: #7c2c22; --brass: #8a681c; + --slate: #3f6689; + --moss: #3d6c46; + --clay: #7c5533; --trash: #8c6558; --play-hot-line: #f0cfc6; @@ -189,14 +197,21 @@ button { cursor: pointer; } /* ---- brand + chrome ---- */ .brand { margin: 0; + display: flex; + align-items: center; + gap: 10px; font: 400 26px/1 var(--font-display); color: var(--paper); } .brand em { color: var(--ember); font-style: italic; } +.brand .mark { width: 30px; height: 26px; flex: none; overflow: visible; } +/* The line art is drawn at a 5px stroke on a 200-unit grid; at brand size that + thins out, so it is nudged up rather than scaled down blindly. */ +.brand .mark g { stroke-width: 6.5; } .topbar { display: flex; - align-items: baseline; + align-items: center; justify-content: space-between; gap: 16px; padding: 22px 20px 14px; @@ -285,6 +300,35 @@ button { cursor: pointer; } border: 1px solid currentColor; } +/* ---- action key: one permanent line under the tabs, so the icon strip below + never has to be guessed at. Lean on a phone (28px, edge to edge), a step + bigger on desktop where there is room to read it. ---- */ +.keyrow { + display: flex; + align-items: flex-start; + justify-content: space-between; + gap: 10px; + padding: 9px 18px 10px; + border-bottom: 1px solid var(--rule); +} +/* On a phone each key stacks: icon over word, so the word gets the full cell + width and can stay the long form. */ +.keyrow .pair { + display: flex; + flex-direction: column; + align-items: center; + gap: 6px; + color: var(--mute); +} +.keyrow .pair svg { width: 14px; height: 14px; flex: none; } +.keyrow .pair span { + font: 500 10px/1 var(--font-mono); + letter-spacing: .04em; + text-transform: uppercase; +} +.keyrow .pair.brass svg { color: var(--brass); } +.keyrow .pair.trash svg { color: var(--trash); } + /* ---- continue reading ---- */ .recent { display: flex; @@ -311,7 +355,7 @@ button { cursor: pointer; } } .recent-strip::-webkit-scrollbar { display: none; } .recent-card { - width: 92px; + width: var(--cover-w); flex: none; display: flex; flex-direction: column; @@ -319,8 +363,8 @@ button { cursor: pointer; } } .recent-cover { position: relative; - width: 92px; - height: 123px; + width: var(--cover-w); + height: calc(var(--cover-w) * 4 / 3); background: var(--hatch); display: grid; place-items: center; @@ -328,7 +372,7 @@ button { cursor: pointer; } } .recent-cover img { width: 100%; height: 100%; object-fit: cover; } .recent-title { - font: 400 15px/1.2 var(--font-display); + font: 400 16px/1.25 var(--font-display); color: var(--paper-dim); display: -webkit-box; -webkit-line-clamp: 2; @@ -336,7 +380,7 @@ button { cursor: pointer; } overflow: hidden; } .recent-chapter { - font: 500 10px/1 var(--font-mono); + font: 500 11px/1 var(--font-mono); letter-spacing: .1em; color: var(--mute-2); } @@ -374,7 +418,7 @@ button { cursor: pointer; } } .card.is-dim { background: var(--dim); } -.row { display: flex; flex-wrap: wrap; gap: var(--row-gap); } +.row { display: flex; flex-wrap: wrap; align-items: center; gap: var(--row-gap); } .cover { position: relative; @@ -387,7 +431,7 @@ button { cursor: pointer; } overflow: hidden; } .cover img { width: 100%; height: 100%; object-fit: cover; } -.cover .monogram { font-size: 30px; } +.cover .monogram { font-size: 32px; } .is-dim .cover { background: var(--hatch-dim); filter: grayscale(1); opacity: .85; } .body { @@ -395,6 +439,7 @@ button { cursor: pointer; } min-width: 0; display: flex; flex-direction: column; + justify-content: center; gap: 8px; } @@ -403,7 +448,7 @@ button { cursor: pointer; } margin: 0; flex: 1; min-width: 0; - font: 400 19px/1.2 var(--font-display); + font: 400 21px/1.2 var(--font-display); color: var(--paper-dim); } /* Heat: crimson title over an ember hairline sized to the text, not the row. */ @@ -416,7 +461,9 @@ button { cursor: pointer; } } .is-dim .title { font-style: italic; color: var(--mute); } .is-dim .fav-mark { color: var(--mute-2); } -.fav-mark { flex: none; width: 13px; height: 13px; margin-top: 5px; color: var(--brass); } +/* The mark always sits at the right edge of the measure, not after the last + word — a new-chapter title shrink-wraps, so without this it drifts. */ +.fav-mark { flex: none; margin-left: auto; width: 14px; height: 14px; margin-top: 5px; color: var(--brass); } .meta { margin: 0; @@ -424,7 +471,7 @@ button { cursor: pointer; } align-items: center; gap: 9px; flex-wrap: wrap; - font: 500 10px/1 var(--font-mono); + font: 500 11px/1 var(--font-mono); letter-spacing: .12em; text-transform: uppercase; color: var(--mute); @@ -434,7 +481,7 @@ button { cursor: pointer; } .site-demonic { color: var(--demonic); } .new-chapter { color: var(--ember); } .state { display: flex; align-items: center; gap: 4px; color: var(--mute); } -.state svg { width: 9px; height: 9px; } +.state svg { width: 10px; height: 10px; } .is-dim .meta { color: var(--mute-2); } .is-dim .site-asura, .is-dim .site-demonic { color: var(--mute); filter: grayscale(.6); } @@ -459,6 +506,12 @@ button { cursor: pointer; } .actions > *:last-child { border-right: none; } .actions svg { width: 17px; height: 17px; } .actions > *:hover { color: var(--paper); } +/* Per-action accent on hover and press: gold favourite, slate archive, moss + finished, clay chapter. Remove keeps --danger, play keeps paper/ember. */ +.actions .fav:hover, .actions .fav:active, .actions .fav:focus-visible { color: var(--brass); } +.actions .pencil:hover, .actions .pencil:active, .actions .pencil:focus-visible { color: var(--clay); } +.actions .box:hover, .actions .box:active, .actions .box:focus-visible { color: var(--slate); } +.actions .finish:hover, .actions .finish:active, .actions .finish:focus-visible { color: var(--moss); } .actions .play { color: var(--paper); } .is-new .actions .play { color: var(--ember); } .actions .play:hover { background: var(--hover); } @@ -696,9 +749,10 @@ button { cursor: pointer; } /* ---- desktop: same measure, actions fold up beside the row ---- */ @media (min-width: 720px) { - :root { --cover-w: 74px; --row-gap: 20px; } + :root { --cover-w: 80px; --row-gap: 20px; } .topbar { padding: 26px 32px 18px; } .brand { font-size: 30px; } + .brand .mark { width: 35px; height: 30px; } .chrome { flex-direction: row; @@ -711,13 +765,25 @@ button { cursor: pointer; } .tabs a { padding: 10px 0 14px; font-size: 18px; } .searchbar { order: 2; flex: 1; margin: 0; border-bottom: none; } .recent h2, .recent-strip { padding-left: 32px; padding-right: 32px; } - .recent-card, .recent-cover { width: 100px; } - .recent-cover { height: 133px; } + .keyrow { + align-items: center; + justify-content: flex-start; + gap: 26px; + height: 36px; + padding: 0 32px; + } + .keyrow .pair { flex-direction: row; gap: 7px; } + .keyrow .pair svg { width: 14px; height: 14px; } + .keyrow .pair span { font-size: 11px; letter-spacing: .1em; } + .keyrow .full { display: inline; } + .recent-card, .recent-cover { width: var(--cover-w); } + .recent-cover { height: calc(var(--cover-w) * 4 / 3); } + .recent-title { font-size: 17px; } .card { padding: 18px 32px; } .row { flex-wrap: nowrap; align-items: center; } - .cover .monogram { font-size: 26px; } - .title { font-size: 21px; } + .cover .monogram { font-size: 28px; } + .title { font-size: 22px; } .actions { flex: none; gap: 4px; border-top: none; } .actions > * { @@ -732,6 +798,10 @@ button { cursor: pointer; } .actions > *:not(.lifecycle) + .lifecycle { margin-left: 10px; box-shadow: none; } .is-new .actions .play { border-color: var(--play-hot-line); } .actions .on { border-color: var(--fav-line); } + /* The cell border follows the icon on hover, so the accent reads as a state + rather than a stray colour. */ + .actions .fav:hover, .actions .pencil:hover, + .actions .box:hover, .actions .finish:hover { border-color: currentColor; } /* Panels line up with the body text, i.e. past the cover and its gap. */ .chapter-form, .confirm-row, .error-inline { diff --git a/backend/templates/app.html b/backend/templates/app.html index 538d541..10d5342 100644 --- a/backend/templates/app.html +++ b/backend/templates/app.html @@ -6,6 +6,7 @@