/* =========================================== ITEM PAGE =========================================== */ /* Item detail page (templates/pages/item.html). Scoped under .item-page body class so the .item-title / .item-meta / .item-price / .item-footer names don't collide with the store-front item-card on project.html. */ .item-page .item-layout { display: grid; grid-template-columns: 400px 1fr; gap: var(--gap-page); margin-bottom: var(--gap-page); } .item-page .item-layout.no-media { grid-template-columns: 1fr; } .item-page .item-title { font-size: var(--text-title); margin-bottom: var(--gap-peer); } .item-page .item-creator { font-size: var(--text-body); opacity: 0.7; margin-bottom: var(--gap-pane); } .item-page .item-creator a { color: var(--content); } .item-page .item-price { font-size: var(--text-display); margin-bottom: var(--gap-pane); } .item-page .item-meta { display: grid; grid-template-columns: 1fr 1fr; gap: var(--gap-section); margin-bottom: var(--gap-pane); padding-bottom: var(--gap-pane); border-bottom: 1px solid var(--border); } .item-page .meta-item { font-size: var(--text-note); } .item-page .meta-label { opacity: 0.7; margin-bottom: var(--gap-bound); } .item-page .meta-value { font-weight: bold; } .item-page .item-tags { margin-bottom: var(--gap-pane); } /* purchase-box uses .card-muted for the box; only its h3/ul/li specifics remain. */ .purchase-box h3 { font-size: var(--text-body); font-weight: normal; margin-bottom: var(--gap-section); } .purchase-box ul { list-style: none; margin-bottom: var(--gap-section); } .purchase-box li { padding: var(--gap-bound) 0; } .purchase-box li::before { content: "→ "; opacity: 0.5; } .item-page .btn-primary { width: 100%; padding: var(--gap-section) var(--gap-page); font-size: var(--text-lead); } .item-page .btn-secondary { width: 100%; margin-top: var(--gap-peer); } .item-page .payment-note { font-size: var(--text-note); opacity: 0.6; text-align: center; margin-top: var(--gap-section); } /* bundle-child uses .list-row co-class; only the gap-4 override remains. */ .bundle-child { gap: var(--gap-section); padding: var(--gap-section) 0; } .item-page .bundle-child-type { font-size: var(--text-fine); padding: var(--gap-bound) var(--gap-group); background: var(--surface-sunken); white-space: nowrap; } .item-page .bundle-child-title { flex: 1; } .item-page .bundle-child-title a { color: var(--content); } .item-page .bundle-child-price { font-size: var(--text-note); opacity: 0.7; } .item-page .bundle-notice { background: var(--surface-sunken); padding: var(--gap-pane); margin-bottom: var(--gap-pane); text-align: center; } .item-page .bundle-notice a { color: var(--content); } .item-page .item-description p { margin-bottom: var(--gap-section); text-align: left; } .item-page .item-description ul { margin-left: var(--gap-pane); margin-bottom: var(--gap-section); } .item-page .item-description li { margin-bottom: var(--gap-peer); } .item-page .features-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: var(--gap-pane); } .item-page .version-number { font-size: var(--text-lead); } .item-page .item-footer { margin-top: var(--gap-page); padding-top: var(--gap-page); border-top: 1px solid var(--border); text-align: center; opacity: 0.6; font-size: var(--text-note); } .item-page .item-footer a { color: var(--content); } @media (max-width: 839px) { .item-page .item-layout { grid-template-columns: 1fr; } } @media (max-width: 599px) { .item-page .item-title { font-size: var(--text-head); } .item-page .item-price { font-size: var(--text-title); } .item-page .item-meta { grid-template-columns: 1fr; gap: var(--gap-peer); } .item-page .item-media, .item-page .item-details { padding: var(--gap-section); } .item-page .item-description { padding: var(--gap-section); } .item-page .item-description h2 { font-size: var(--text-subhead); } .item-page .purchase-box { padding: var(--gap-section); } } /* =========================================== PROJECT PAGE (store front) =========================================== The store front is described (`src/quasi/project.rs`), so the header, the item cards, the two view copies, the tab strip and the tier cards are all the design system's markup now: a rule restating one of them fails the drift check in build.rs. What is this page's rather than the system's is how wide it runs, which is the measure on the body, and nothing else was left. */ /* =========================================== LIBRARY DOWNLOADS PAGE =========================================== */ /* Library downloads page (templates/pages/library_downloads.html). Scoped under .library-page body class. Class names like .item-footer, .bundle-child, etc. overlap with .item-page; the scope keeps them distinct. */ .library-page .library-header { display: grid; grid-template-columns: 200px 1fr; gap: var(--gap-pane); margin-bottom: var(--gap-page); align-items: center; } .library-page .library-header.no-cover { grid-template-columns: 1fr; } .library-page .library-cover img { width: 100%; aspect-ratio: 1 / 1; object-fit: cover; display: block; } .library-page .library-title { font-size: var(--text-title); margin-bottom: var(--gap-bound); } /* Byline sits under the centered H1 (global `h1 { text-align: center }`), so center it too, otherwise it floats flush-left while the title is centered above. Same for the back-link breadcrumb. When a cover is present the grid scope below restores left-alignment in the text column. */ .library-page .library-creator { font-size: var(--text-body); opacity: 0.7; margin-bottom: var(--gap-section); text-align: center; } .library-page .library-creator a { color: var(--content); } .library-page .library-back { font-size: var(--text-note); opacity: 0.7; text-align: center; } .library-page .library-back a { color: var(--content); } /* When a cover is present, the title block sits in the right grid column; left-align in that context so the column reads as a coherent block next to the cover instead of a centered island. */ .library-page .library-header:not(.no-cover) .library-title, .library-page .library-header:not(.no-cover) .library-creator { text-align: left; } .library-page .downloads-hero h2 { font-size: var(--text-head); margin-bottom: var(--gap-section); padding-bottom: var(--gap-peer); border-bottom: 1px solid var(--border); } .library-page .download-row { display: flex; align-items: center; gap: var(--gap-section); padding: var(--gap-group) 0; border-bottom: 1px solid var(--border); } .library-page .download-row:last-child { border-bottom: none; } .library-page .download-version { min-width: 4em; font-family: var(--font-mono); font-size: var(--text-note); } .library-page .download-label { flex: 1; } .library-page .download-size { font-size: var(--text-note); opacity: 0.6; min-width: 5em; text-align: right; } .library-page .download-notice { background: var(--surface-sunken); padding: var(--gap-pane); margin-bottom: var(--gap-page); font-size: var(--text-note); opacity: 0.8; } .library-page .download-notice strong { font-family: var(--font-mono); } /* Inline download list on library_audio.html / library_video.html (below the media player). */ .library-page .library-downloads h3 { font-size: var(--text-lead); margin-bottom: var(--gap-section); } .library-page .library-section h2 { font-size: var(--text-subhead); margin-bottom: var(--gap-section); padding-bottom: var(--gap-peer); border-bottom: 1px solid var(--border); } .library-page .bundle-child { display: flex; align-items: center; gap: var(--gap-section); padding: var(--gap-section) 0; border-bottom: 1px solid var(--border); } .library-page .bundle-child:last-child { border-bottom: none; } .library-page .bundle-child-type { font-size: var(--text-fine); padding: var(--gap-bound) var(--gap-group); background: var(--surface-sunken); white-space: nowrap; } .library-page .bundle-child-title { flex: 1; } .library-page .bundle-child-title a { color: var(--content); } .library-page .item-footer { margin-top: var(--gap-page); padding-top: var(--gap-page); border-top: 1px solid var(--border); text-align: center; opacity: 0.6; font-size: var(--text-note); } .library-page .item-footer a { color: var(--content); } @media (max-width: 599px) { .library-page .library-header { grid-template-columns: 1fr; } .library-page .library-cover img { max-width: 200px; } } /* =========================================== ARTICLE & BLOG READER =========================================== */ /* Article reader pages (templates/pages/text_reader.html, blog_post.html, library_text.html). Long-form article layout, centered narrow column, author header, large heading, magazine-style body type. Scoped under .article-page body class. The container itself takes the shared reading column near the top of this file. */ .article-page .author-header { display: flex; align-items: center; gap: var(--gap-section); margin-bottom: var(--gap-page); } .article-page .author-avatar { width: 48px; height: 48px; background: var(--surface-sunken); border-radius: var(--radius-round); display: flex; align-items: center; justify-content: center; font-family: var(--font-display); font-size: var(--text-subhead); color: var(--content); } .article-page .author-info { flex: 1; } .article-page .author-name { font-family: var(--font-mono); font-size: var(--text-body); color: var(--content); } .article-page .author-name a:hover { text-decoration: underline; } .article-page .article-meta { font-family: var(--font-mono); font-size: var(--text-note); color: var(--content-muted); } .article-page .article-title { font-family: var(--font-display); font-size: var(--text-display); font-weight: normal; line-height: 1.2; margin-bottom: var(--gap-pane); color: var(--content); text-align: left; } .article-page .article-deck { font-family: var(--font-mono); font-size: var(--text-subhead); color: var(--content-muted); margin-bottom: var(--gap-page); line-height: 1.6; } .article-page .article-body { font-family: var(--font-sans); font-size: var(--text-lead); line-height: 1.9; } .article-page .article-body p { margin-bottom: var(--gap-pane); } .article-page .article-body h1 { font-family: var(--font-display); font-size: var(--text-title); font-weight: normal; margin-top: var(--gap-page); margin-bottom: var(--gap-section); color: var(--content); text-align: left; } .article-page .article-body h2 { font-family: var(--font-mono); font-size: var(--text-head); font-weight: normal; margin-top: var(--gap-page); margin-bottom: var(--gap-section); color: var(--content); } .article-page .article-body h3 { font-family: var(--font-mono); font-size: var(--text-subhead); font-weight: normal; margin-top: var(--gap-page); margin-bottom: var(--gap-section); color: var(--content); } .article-page .article-body blockquote { border-left: 3px solid var(--action); padding-left: var(--gap-pane); margin: var(--gap-page) 0; font-style: italic; color: var(--content-muted); } .article-page .article-body ul, .article-page .article-body ol { margin-bottom: var(--gap-pane); padding-left: var(--gap-pane); } .article-page .article-body li { margin-bottom: var(--gap-peer); } .article-page .article-body a { color: var(--action); text-decoration: underline; text-decoration-color: color-mix(in oklch, var(--action) 40%, transparent); text-underline-offset: 2px; } .article-page .article-body a:hover { text-decoration-color: var(--action); } .article-page .article-body strong { font-weight: bold; } .article-page .article-body em { font-style: italic; } .article-page .article-body code { font-family: var(--font-mono); background: var(--surface-sunken); padding: var(--gap-bound) var(--gap-peer); font-size: var(--text-body); } .article-page .article-body pre { background: var(--surface-sunken); padding: var(--gap-section); overflow-x: auto; margin-bottom: var(--gap-pane); } .article-page .article-body pre code { background: none; padding: 0; } .article-page .article-body hr { border: none; text-align: center; margin: var(--gap-page) 0; } .article-page .article-body hr::before { content: "* * *"; color: var(--content-muted); letter-spacing: 1rem; } .article-page .article-footer { margin-top: var(--gap-page); padding-top: var(--gap-page); border-top: 1px solid var(--border); } .article-page .author-bio { display: flex; gap: var(--gap-section); padding: var(--gap-pane); background: var(--surface-overlay); } .article-page .author-bio .author-avatar { width: 64px; height: 64px; font-size: var(--text-head); flex-shrink: 0; } .article-page .author-bio-content { flex: 1; } .article-page .author-bio-name { font-family: var(--font-mono); font-size: var(--text-lead); margin-bottom: var(--gap-peer); } .article-page .author-bio-name a:hover { text-decoration: underline; } .article-page .article-tags { margin-top: var(--gap-page); display: flex; gap: var(--gap-peer); flex-wrap: wrap; } .article-page .article-tag { font-family: var(--font-mono); background: var(--surface-sunken); color: var(--content); padding: var(--gap-peer) var(--gap-section); font-size: var(--text-fine); text-decoration: none; } /* Share controls at the end of the article, inside .article-footer beside the tags or the blog crumb. Was a page-bottom footer below the comments until the site-footer consolidation; the control belongs with the piece it copies, not under the discussion. */ .article-page .reader-actions { font-family: var(--font-mono); font-size: var(--text-note); margin-top: var(--gap-section); } .article-page .reader-actions a { color: var(--content); text-decoration: none; } .article-page .reader-actions a:hover { text-decoration: underline; } /* Blog-specific: nav crumb above the article. */ .article-page .blog-nav { font-family: var(--font-mono); font-size: var(--text-note); margin-bottom: var(--gap-page); } .article-page .blog-nav a { color: var(--content); text-decoration: none; } .article-page .blog-nav a:hover { text-decoration: underline; } @media (max-width: 599px) { .article-page .article-title { font-size: var(--text-title); } .article-page .article-deck { font-size: var(--text-lead); } .article-page .article-body { font-size: var(--text-body); } }