diff --git a/prototype/ornament/ornament.css b/prototype/ornament/ornament.css index 77092fe..e414d39 100644 --- a/prototype/ornament/ornament.css +++ b/prototype/ornament/ornament.css @@ -55,7 +55,7 @@ .wg-panel { position: relative; background: var(--wg-panel); - border-radius: 8px; + border-radius: 0; padding: var(--wg-pad, 1rem); } .wg-panel::before { @@ -141,7 +141,7 @@ ====================================================================== */ .wg-ledger { background: var(--wg-panel-2); - border-radius: 8px; + border-radius: 0; overflow: hidden; } .wg-ledger__row { diff --git a/prototype/ornament/real-surface.css b/prototype/ornament/real-surface.css index 2fe2473..3ce00f9 100644 --- a/prototype/ornament/real-surface.css +++ b/prototype/ornament/real-surface.css @@ -4,24 +4,73 @@ Every rule below is one of the named components doing its job on real NodeBB markup. Nothing new is invented here. */ -/* ---- PANEL: edges fade. No hairline runs corner to corner. ---- */ +/* ---- SQUARE. One shape, every surface. A cut or rounded corner is a second + shape language and the shell only gets one. ---- */ +/* specificity has to beat the theme's own `border-radius: 8px !important` */ +html body [class], +html body [class]::before, +html body [class]::after, +html body [class] [class], +html body [class] [class][class], +html body blockquote, +html body pre, +html body code, +html body img, +html body input, +html body textarea, +html body button { + border-radius: 0 !important; +} +/* Signets stay square like everything else — the theme's own signet plate is + the settled treatment and it is square. Only the status dot is round, + because it is a dot. */ +html body [class] [class].status, +html body .status { + border-radius: 50% !important; +} + +/* ---- PANEL: edges fade. No hairline runs corner to corner, but the edge is + present enough to hold the panel off the page. ---- */ li[component="categories/category"], li[component="category/topic"], .westgate-surface, -.card { +.card, +ul.categories-list, +ul.westgate-categories-list, +[component="post/content"], +.post-container { border-color: transparent !important; position: relative; } -li[component="categories/category"]::after, -.westgate-surface::after { +ul.categories-list::after, +ul.westgate-categories-list::after, +.westgate-surface::after, +.post-container::after, +body.template-category .category-header::after { content: ""; position: absolute; inset: 0; - border-radius: inherit; - border: 1px solid var(--wg-border); - -webkit-mask-image: linear-gradient(180deg, #000, rgba(0, 0, 0, 0.12)); - mask-image: linear-gradient(180deg, #000, rgba(0, 0, 0, 0.12)); + border: 1px solid rgba(var(--wg-pewter-rgb), 0.34); + -webkit-mask-image: linear-gradient(180deg, #000, rgba(0, 0, 0, 0.16)); + mask-image: linear-gradient(180deg, #000, rgba(0, 0, 0, 0.16)); pointer-events: none; + z-index: 2; +} + +/* ---- A square edge with no falloff reads as a cut, not an edge. Every + bounded surface sits on a wide, offset-down black shadow: no lift, no + stacking claim, just the corner catching the room (Candlelight). ---- */ +html body ul.categories-list, +html body ul.westgate-categories-list, +html body .westgate-surface, +html body .post-container, +html body .topic-list-header, +html body [data-widget-area] .card, +html body.template-category .category-header { + box-shadow: + inset 0 1px 0 rgba(255, 255, 255, 0.02), + 0 10px 26px rgba(0, 0, 0, 0.34), + 0 2px 4px rgba(0, 0, 0, 0.28) !important; } /* ---- LEDGER: rows are ruled, not boxed. The category list is a ledger: @@ -30,8 +79,6 @@ ul.categories-list, ul.westgate-categories-list { gap: 0 !important; background: var(--wg-panel-2); - border-radius: 8px; - overflow: hidden; } ul.categories-list li[component="categories/category"], ul.westgate-categories-list li[component="categories/category"] { @@ -71,6 +118,17 @@ li[component="categories/category"] h2.title::after, background: linear-gradient(90deg, rgba(var(--wg-gold-rgb), 0.34), transparent); } +/* ---- CASE: Cinzel is always uppercase. One rule, no exceptions, because + its lowercase is a small-caps design and reads as a weaker version of the + same thing rather than a second voice. ---- */ +html body [class] h1, +html body [class] h2, +html body [class] h3, +html body .topic-title, +html body .breadcrumb { + text-transform: uppercase !important; +} + /* ---- PLAQUE: the page title becomes a name plate, not a band. ---- */ body.template-category .category-header .category-title, body.template-topic .topic-title h1 { diff --git a/prototype/ornament/shots.js b/prototype/ornament/shots.js index 88b3b98..2498eb1 100644 --- a/prototype/ornament/shots.js +++ b/prototype/ornament/shots.js @@ -14,6 +14,7 @@ const ornament = read('real-surface.css'); const VARIANTS = { before: paletteB, after: paletteB + ornament }; const PAGES = [ ['categories', '/categories'], + ['category', '/category/8'], ['topic', '/topic/2'], ]; diff --git a/prototype/ornament/shots/categories-after-crop.png b/prototype/ornament/shots/categories-after-crop.png index dd11d6a..f74f777 100644 Binary files a/prototype/ornament/shots/categories-after-crop.png and b/prototype/ornament/shots/categories-after-crop.png differ diff --git a/prototype/ornament/shots/categories-after.png b/prototype/ornament/shots/categories-after.png index 12bf4cd..35970cc 100644 Binary files a/prototype/ornament/shots/categories-after.png and b/prototype/ornament/shots/categories-after.png differ diff --git a/prototype/ornament/shots/categories-before.png b/prototype/ornament/shots/categories-before.png index 0d925ba..9da116e 100644 Binary files a/prototype/ornament/shots/categories-before.png and b/prototype/ornament/shots/categories-before.png differ diff --git a/prototype/ornament/shots/category-after-crop.png b/prototype/ornament/shots/category-after-crop.png new file mode 100644 index 0000000..6b9ea33 Binary files /dev/null and b/prototype/ornament/shots/category-after-crop.png differ diff --git a/prototype/ornament/shots/category-after.png b/prototype/ornament/shots/category-after.png new file mode 100644 index 0000000..b38f2db Binary files /dev/null and b/prototype/ornament/shots/category-after.png differ diff --git a/prototype/ornament/shots/category-before-crop.png b/prototype/ornament/shots/category-before-crop.png new file mode 100644 index 0000000..53f9efb Binary files /dev/null and b/prototype/ornament/shots/category-before-crop.png differ diff --git a/prototype/ornament/shots/category-before.png b/prototype/ornament/shots/category-before.png new file mode 100644 index 0000000..317fb90 Binary files /dev/null and b/prototype/ornament/shots/category-before.png differ diff --git a/prototype/ornament/shots/cats-ledger.png b/prototype/ornament/shots/cats-ledger.png new file mode 100644 index 0000000..6a9149b Binary files /dev/null and b/prototype/ornament/shots/cats-ledger.png differ diff --git a/prototype/ornament/shots/cats-roomy.png b/prototype/ornament/shots/cats-roomy.png new file mode 100644 index 0000000..6ae4faf Binary files /dev/null and b/prototype/ornament/shots/cats-roomy.png differ diff --git a/prototype/ornament/shots/cats-tabular-gold.png b/prototype/ornament/shots/cats-tabular-gold.png new file mode 100644 index 0000000..57b5df1 Binary files /dev/null and b/prototype/ornament/shots/cats-tabular-gold.png differ diff --git a/prototype/ornament/shots/cats-tabular.png b/prototype/ornament/shots/cats-tabular.png new file mode 100644 index 0000000..c875782 Binary files /dev/null and b/prototype/ornament/shots/cats-tabular.png differ diff --git a/prototype/ornament/shots/topic-after-crop.png b/prototype/ornament/shots/topic-after-crop.png index 28e993c..46cd9b3 100644 Binary files a/prototype/ornament/shots/topic-after-crop.png and b/prototype/ornament/shots/topic-after-crop.png differ diff --git a/prototype/ornament/shots/topic-after.png b/prototype/ornament/shots/topic-after.png index b5b35a9..c47bd04 100644 Binary files a/prototype/ornament/shots/topic-after.png and b/prototype/ornament/shots/topic-after.png differ diff --git a/prototype/ornament/shots/topic-before-crop.png b/prototype/ornament/shots/topic-before-crop.png index 5b5d4bc..c8fb4d7 100644 Binary files a/prototype/ornament/shots/topic-before-crop.png and b/prototype/ornament/shots/topic-before-crop.png differ diff --git a/prototype/ornament/shots/topic-before.png b/prototype/ornament/shots/topic-before.png index f01efae..c0c3539 100644 Binary files a/prototype/ornament/shots/topic-before.png and b/prototype/ornament/shots/topic-before.png differ diff --git a/prototype/ornament/variant-gold.css b/prototype/ornament/variant-gold.css new file mode 100644 index 0000000..982892e --- /dev/null +++ b/prototype/ornament/variant-gold.css @@ -0,0 +1,30 @@ +/* Variant: gilt structures, pewter only speaks. + Two Metals inverted from #53's assignment — the metals keep separate jobs, + but the visible edge work goes back to gold and pewter is demoted to + metadata text only. Answers "there is too much silver now". */ +:root { + --wg-border: rgba(var(--wg-gold-rgb), 0.2); + --wg-border-soft: rgba(var(--wg-gold-rgb), 0.11); + --wg-ledger-ruling: rgba(var(--wg-gold-rgb), 0.08); + --wg-ledger-rule-strong: rgba(var(--wg-gold-rgb), 0.2); + --wg-ledger-border: rgba(var(--wg-gold-rgb), 0.24); +} +/* panel edges, ledger edge, icon ring: gilt */ +html body ul.categories-list::after, +html body ul.westgate-categories-list::after, +html body .westgate-surface::after, +html body .post-container::after, +html body.template-category .category-header::after { + border-color: rgba(var(--wg-gold-rgb), 0.28) !important; +} +html body li[component="categories/category"] .icon { + box-shadow: + inset 0 1px 0 rgba(255, 255, 255, 0.12), + inset 0 -3px 7px rgba(0, 0, 0, 0.52), + 0 0 0 1px rgba(var(--wg-gold-rgb), 0.28) !important; +} +/* category names keep the ledger ink, one step brighter than body */ +html body li[component="categories/category"] h2.title, +html body li[component="categories/category"] h2.title a { + color: var(--wg-ledger-ink) !important; +} diff --git a/prototype/ornament/variant-roomy.css b/prototype/ornament/variant-roomy.css new file mode 100644 index 0000000..1b50cdf --- /dev/null +++ b/prototype/ornament/variant-roomy.css @@ -0,0 +1,30 @@ +/* Variant: rows breathe. The category list goes back to separate panels with + air between them, instead of one ruled ledger. Same components, same square + shape, same fading edge — only the ledger reading is dropped. */ +html body ul.categories-list, +html body ul.westgate-categories-list { + gap: var(--wg-space-sm, 0.75rem) !important; + background: none !important; +} +html body ul.categories-list::after, +html body ul.westgate-categories-list::after { + content: none; +} +html body ul.categories-list li[component="categories/category"], +html body ul.westgate-categories-list li[component="categories/category"] { + background: var(--wg-panel-2) !important; + background-image: none !important; + padding: var(--wg-space-md, 1rem) !important; +} +/* each row gets its own fading edge, since it is a panel again */ +html body ul.categories-list li[component="categories/category"]::after, +html body ul.westgate-categories-list li[component="categories/category"]::after { + content: ""; + position: absolute; + inset: 0; + border: 1px solid rgba(var(--wg-pewter-rgb), 0.34); + -webkit-mask-image: linear-gradient(180deg, #000, rgba(0, 0, 0, 0.16)); + mask-image: linear-gradient(180deg, #000, rgba(0, 0, 0, 0.16)); + pointer-events: none; + z-index: 2; +} diff --git a/prototype/ornament/variant-tabular.css b/prototype/ornament/variant-tabular.css new file mode 100644 index 0000000..0153d13 --- /dev/null +++ b/prototype/ornament/variant-tabular.css @@ -0,0 +1,179 @@ +/* Variant: the ledger row as a line in a record, not three blocks in a row. + The data columns move into WELLS; the left side stays prose. */ + +/* ---- WELL — a recess, the inverse of Panel. Panel is laid on the surface + and casts down; a well is cut into it and shadows inward. Three of them, + one per reading, bleeding to the row's right edge. The gap between two + wells is their divider: a well never carries a rule inside it. ---- */ +html body li[component="categories/category"] > div.col-lg-5 { + background: none !important; + box-shadow: none !important; + align-items: stretch !important; + padding: 0 !important; + gap: 0.4rem !important; + /* the wells sit inside the row's margin on every side — a well cut flush to + the right edge reads as the row running off the page */ + margin: 0 !important; +} + +/* the stat pair: two equal columns of well, not two little cards */ +html body li[component="categories/category"] .meta.stats, +html body li[component="categories/category"] .stats { + display: grid !important; + /* the counts need only their own width; the room goes to the teaser */ + grid-template-columns: 6rem 6rem !important; + justify-content: end !important; + gap: 0.4rem !important; + padding: 0 !important; + border: 0 !important; + background: none !important; + box-shadow: none !important; +} + +/* the well itself */ +html body li[component="categories/category"] .stats .card, +html body li[component="categories/category"] .stats .card-header, +html body li[component="categories/category"] .teaser { + /* the basin sits below the row it is cut into, but not as dead as the + page floor: between panel-2 and bg-deep */ + background: color-mix(in srgb, var(--wg-panel-2) 45%, var(--wg-bg-deep)) !important; + background-image: none !important; + border: 0 !important; + box-shadow: + inset 0 1px 3px rgba(0, 0, 0, 0.55), + inset 0 0 0 1px rgba(var(--wg-gold-rgb), 0.1) !important; + padding: 0.5rem 0.85rem !important; +} +/* the teaser is prose, so it gets the room and a proper margin of its own */ +html body li[component="categories/category"] .teaser { + flex: 1 1 auto !important; + /* the basin's inset is even on all four sides — a wider left/right inset + reads as the text not filling the well */ + padding: 0.55rem !important; +} +/* the teaser's inner blocks are flex items once the well is a flex box, so + they shrink to their text and stop filling. Make them fill it. */ +html body li[component="categories/category"] .lastpost, +html body li[component="categories/category"] .westgate-lastpost { + flex: 1 1 auto !important; + width: 100% !important; + min-width: 0 !important; + height: auto !important; +} +html body li[component="categories/category"] [component="category/posts"] { + padding-left: 0 !important; + width: 100% !important; + min-width: 0 !important; + /* the byline and its line of prose are one block, not two rows */ + gap: 0.1rem !important; + height: auto !important; + line-height: 1.35 !important; +} +html body li[component="categories/category"] .teaser .text-nowrap { + line-height: 1.2 !important; + /* the signet's ring is drawn outside its 18px box, and this row is + `text-truncate` (overflow: hidden), so at x=0 the left of the ring is cut. + Give it the ring's width back. */ + padding-left: 2px !important; +} +html body li[component="categories/category"] .stats .card { + display: flex !important; + flex-direction: column !important; + align-items: center !important; + justify-content: center !important; +} + +/* the number carries; the label is engraved and small */ +html body li[component="categories/category"] .stats .card > span:first-child { + font-family: var(--wg-font-display) !important; + color: var(--wg-text) !important; +} +html body li[component="categories/category"] .stats .card > span + span, +html body li[component="categories/category"] .stats small { + font-family: var(--wg-font-display) !important; + font-size: 0.78rem !important; + letter-spacing: 0.12em !important; + text-transform: uppercase !important; + color: var(--wg-text-muted) !important; +} + +/* the teaser well reads as text, so it is set left and loses NodeBB's + inline pure-white rule — a ledger has one ruling weight, not two */ +html body li[component="categories/category"] .teaser { + display: flex !important; + align-items: center !important; +} +html body li[component="categories/category"] .teaser *, +html body li[component="categories/category"] .lastpost, +html body li[component="categories/category"] .westgate-lastpost { + text-align: left !important; + border-left: 0 !important; + padding-left: 0 !important; +} +/* the byline row must stretch, or it shrinks to its own text and the + `text-truncate` on it starts clipping the signet */ +html body li[component="categories/category"] [component="category/posts"], +html body li[component="categories/category"] .lastpost, +html body li[component="categories/category"] .westgate-lastpost { + align-items: stretch !important; + justify-content: center !important; +} +html body li[component="categories/category"] .teaser .text-nowrap, +html body li[component="categories/category"] .teaser .post-content { + width: 100% !important; + max-width: 100% !important; +} +html body li[component="categories/category"] .teaser p, +html body li[component="categories/category"] [component="category/posts"] p { + display: -webkit-box; + -webkit-line-clamp: 2; + -webkit-box-orient: vertical; + overflow: hidden; + margin: 0 !important; + color: var(--wg-text-muted) !important; +} + +/* the left side is prose and stops at its own measure; the wells take the + room that was standing empty between the two */ +html body li[component="categories/category"] > div.col-lg-7 { + flex: 0 0 46% !important; + max-width: 46% !important; +} +html body li[component="categories/category"] > div.col-lg-5 { + flex: 1 1 auto !important; + max-width: none !important; +} + +/* one baseline for the whole row, so rows scan as lines rather than pages. + The columns stretch: a centred well cannot grow, so a two-line teaser + overflows it top and bottom and gets clipped. */ +html body li[component="categories/category"] { + align-items: stretch !important; +} +html body li[component="categories/category"] .teaser, +html body li[component="categories/category"] .lastpost, +html body li[component="categories/category"] .westgate-lastpost, +html body li[component="categories/category"] [component="category/posts"] { + height: auto !important; + min-height: 0 !important; + overflow: visible !important; +} +/* the clamp keeps its own overflow — it is what puts the ellipsis on. But its + line box has to be taller than the glyphs, or `overflow: hidden` shaves the + ascenders off the first line and the descenders off the last. */ +html body li[component="categories/category"] .post-content { + height: auto !important; + min-height: 0 !important; + line-height: 1.5 !important; + /* NodeBB's `line-clamp-sm-2` clamps by a hard `max-height` sized to its own + line-height. Ours is taller, so that max-height cuts the glyphs. Drop it + and clamp by line count instead. */ + max-height: none !important; + display: -webkit-box !important; + -webkit-line-clamp: 2 !important; + -webkit-box-orient: vertical !important; + overflow: hidden !important; +} +html body li[component="categories/category"] h2.title { + margin-bottom: 0.15rem !important; +}