diff --git a/documentation/src/pages/at-scale.module.css b/documentation/src/pages/at-scale.module.css index 330dc0b1..5adcf5b6 100644 --- a/documentation/src/pages/at-scale.module.css +++ b/documentation/src/pages/at-scale.module.css @@ -289,21 +289,68 @@ /* ------------------------------------------------------------------ table ---- */ +/* + * Infima styles every table as a bordered, striped grid, and this one is ruled + * horizontally only. Its defaults are cleared here rather than worked around: the cells + * start at the measure with no left padding, which only reads as a column when there is + * no vertical rule for the text to sit against. display:table is part of the reset too, + * since Infima's display:block leaves border-collapse below with nothing to collapse. + * + * The layout is fixed so the widths below hold: a long answer wraps inside its column + * rather than widening it, which is what keeps the gaps between the three even. + */ .table { + display: table; + table-layout: fixed; width: 100%; - margin-top: 2rem; + margin: 2rem 0 0; border-collapse: collapse; font-size: 0.9rem; } +/* + * The middle column holds a word or two. Sizing itself, it took nearly a third of the + * table and left its answer stranded a long way short of the last column, so it is given + * the width its content needs and the slack goes to the column on the end, where there is + * nothing following it to open a gap against. Widths sit on the head row because the + * fixed layout above takes its columns from the first row. + */ +.table thead th:first-child { + width: 30%; +} + +.table thead th:nth-child(2) { + width: 14rem; +} + +.table thead, +.table tr, +.table tr:nth-child(2n) { + background: none; + border-top: none; +} + +.table thead tr { + border-bottom: none; +} + .table th, .table td { padding: 0.9rem var(--tp-gut) 0.9rem 0; text-align: left; vertical-align: top; + border: none; border-bottom: 1px solid var(--tp-rule); } +/* The capability column's text runs to its full measure, so this padding is the entire gap + after it. It is wider than the shared gutter to match the space the middle column's + width leaves before the last one, which is set by that column's content, not by a + gutter. */ +.table tr > *:first-child { + padding-right: 3.5rem; +} + .table thead th { border-bottom: 1px solid var(--tp-ink); color: var(--tp-faint); @@ -315,7 +362,6 @@ } .table tbody th { - width: 30%; font-family: var(--tp-display); font-size: 0.88rem; font-weight: 700; @@ -1018,8 +1064,11 @@ border-bottom: none; } + .table tr > *:first-child { + padding-right: 0; + } + .table tbody th { - width: auto; margin-bottom: 0.4rem; } diff --git a/documentation/src/pages/index.js b/documentation/src/pages/index.js index 3af7b8a0..77dca10b 100644 --- a/documentation/src/pages/index.js +++ b/documentation/src/pages/index.js @@ -49,8 +49,9 @@ const REPO = 'https://github.com/StackGuardian/tirith'; * told it does not exist yet. Influence is the offer, and the star is the cheap version of * it rather than the point. * - * All three are ghost buttons. A secondary action that looks primary is not secondary, and - * the accent on this page belongs to the copy button in the hero. + * Only the first is a ghost button and the rest are plain text. A secondary action that + * looks primary is not secondary, and the accent on this page belongs to the copy button + * in the hero. */ const involve = { note: @@ -68,11 +69,23 @@ const involve = { 'It is licensed under Apache 2.0 and governed publicly. Contributions do not need to ' + 'be large: a tested policy, a CI example for an underserved system, or a reproducible bug ' + 'report can be far more valuable than a star.', - links: [ - {label: 'Star on GitHub', href: REPO}, - {label: 'Find a good first issue', href: `${REPO}/labels/good%20first%20issue`}, - {label: 'Watch for releases', href: `${REPO}/releases`}, + /* + * One button, because four of them read as four equally weighted decisions at the point + * where the page should be asking for one thing. + * + * The button is the good-first-issue list and not the star. The paragraph above it says + * a bug report is worth more than a star, so giving the star the loudest element would + * have the layout contradicting the copy, and starring is not contributing. The rest run + * from the ask that takes real work down to the one that costs nothing. + */ + primary: { + label: 'Find a good first issue', + href: `${REPO}/labels/good%20first%20issue`, + }, + more: [ {label: 'Ask for a feature', href: `${REPO}/issues/new/choose`}, + {label: 'Watch for releases', href: `${REPO}/releases`}, + {label: 'Star on GitHub', href: REPO}, ], }; @@ -265,10 +278,12 @@ const announcement = { // No backticks: this is JSX text, not markdown, so they would render literally. // The renderer sets the command in . command: 'tirith ui', + // A banner is read at a glance or not at all, so it carries the two things the tool is + // for and nothing else. Validation as you type and serving the playground to a team are + // the page it links to, not this line. body: - 'explores a failing evaluation down to the resource that caused it, builds policies ' + - 'from a form, validates them as you type, and serves the playground on a port for ' + - 'people who have installed nothing.', + 'explores a failing evaluation down to the resource that caused it, and builds ' + + 'policies from a form.', to: '/docs/tirith-usage/interactive-interface/', linkLabel: 'Read more', }; @@ -903,29 +918,47 @@ export default function Home() {

-

Built by the community

- + + Get involved + + {/* + * Captioned rather than labelled from above, because the heading now names + * the section rather than the row: without a line of its own the faces are + * a group of strangers the reader has no way to place. + */} +
+
    + {CONTRIBUTORS.map((c) => ( +
  • + + {c.login} + +
  • + ))} +
+
+ Built by the community. +
+

{involve.community}

{involve.note}

+ {/* Wrapped, because a bare grid child would stretch the button full width. */}
- {involve.links.map((l) => ( - - {l.label} + + {involve.primary.label} + +
+
+ {involve.more.map((l) => ( + + {l.label} ))}
diff --git a/documentation/src/pages/index.module.css b/documentation/src/pages/index.module.css index ab3876ea..88fe4151 100644 --- a/documentation/src/pages/index.module.css +++ b/documentation/src/pages/index.module.css @@ -1428,12 +1428,26 @@ border-bottom: 1px solid var(--tp-rule); } +/* + * The tag sits in its own column rather than trailing the title inline, so the four tags + * line up down the strip instead of landing wherever each title happens to stop. Each row + * is its own grid, so the tags only agree on a width if the column names one and they + * fill it; left to size themselves the shorter tag sits indented from the longer ones. + * It is a floor rather than a fixed width because the tags do not wrap: a status longer + * than today's two should push the column open, not spill across the gap into the body. + */ .aheadHead { - display: flex; + display: grid; + grid-template-columns: minmax(0, 1fr) minmax(4.6rem, auto); align-items: baseline; gap: 0.6rem; } +.aheadHead .betaTag, +.aheadHead .tagPlanned { + text-align: center; +} + .aheadTitle { font-family: var(--tp-display); font-size: 0.8rem; @@ -1461,6 +1475,12 @@ .aheadStrip li { grid-template-columns: minmax(0, 1fr); } + + /* Nothing to line up against once the rows are full width, and a tag held out at the + right edge of a phone reads as belonging to the row rather than to its title. */ + .aheadHead { + display: flex; + } } /* @@ -1521,6 +1541,45 @@ outline-offset: 2px; } +/* + * The figure holds the faces and their caption together. The row's own bottom margin is + * spacing for the block below it, which is too much between an image and its caption, so + * it is overridden here rather than pulled back with a negative margin on the caption. + */ +.contributors { + margin: 0; +} + +.contributors .faces { + margin-bottom: 0.55rem; +} + +.contributorsNote { + color: var(--tp-faint); + font-size: 0.8rem; +} + +/* + * The references under the button. They are deliberately not buttons: the block asks for + * one thing, and a row of equally sized boxes turns that ask into a menu. + */ +.involveMore { + display: flex; + flex-wrap: wrap; + gap: 0.35rem 1.2rem; + font-size: 0.85rem; +} + +.involveMore a { + color: var(--tp-soft); + text-decoration: underline; + text-underline-offset: 0.2em; +} + +.involveMore a:hover { + color: var(--tp-ink); +} + .involveNote { max-width: 62ch; margin: 0;