-
How much color should this design use?
+
How much color should this design use?
@@ -808,27 +808,21 @@ const questions = [
-
- {/* The stage the chosen surfaces are drawn on. Its contents are
- lifted from the tiles on screen 01b, so it is filled by
- script. The clones land inside the stage, which is why the
- buttons are its sibling rather than its last child. */}
-
-
-
- Select this strategy
-
-
-
-
-
-
-
Back
-
-
+
+
+ Select this strategy
+
+
+
+
+
+
+
Back
diff --git a/picker/scripts/palette-picker.js b/picker/scripts/palette-picker.js
index d9416d392..1a1c6edcf 100644
--- a/picker/scripts/palette-picker.js
+++ b/picker/scripts/palette-picker.js
@@ -51,6 +51,52 @@ const LOREM = {
caption: 'Lorem ipsum dolor sit amet, consectetur adipiscing.',
};
+/* Every word slot on the font boards, in lorem. A pair is judged on glyphs, and
+ product words pull the eye into reading the page instead of the setting, so
+ the type screen draws placeholder copy in every slot rather than only in the
+ running text. Titles are one word because the slot is one line wide. */
+const LOREM_PREVIEW = {
+ brand: 'Lo',
+ nav: ['Lorem', 'Ipsum', 'Dolor', 'Amet'],
+ navAction: 'Consectetur',
+ menuAction: 'Ipsum',
+ ctaPrimary: 'Lorem ipsum',
+ ctaSecondary: 'Dolor sit',
+ proof: ['Lorem ipsum dolor', 'Sit amet elit', 'Sed do eiusmod', 'Tempor incididunt'],
+ sectionTitle: 'Lorem ipsum dolor sit',
+ sectionLink: 'Consectetur adipiscing',
+ gallery: [
+ { title: 'Lorem', meta: 'Ipsum dolor' },
+ { title: 'Dolor', meta: 'Sit amet' },
+ { title: 'Eiusmod', meta: 'Tempor elit' },
+ ],
+ footerLinks: ['Lorem', 'Ipsum', 'Dolor', 'Amet'],
+ footerMark: '© Lorem ipsum',
+};
+
+const LOREM_SPECIMEN = { headline: 'Lorem ipsum dolor sit amet' };
+
+const LOREM_APP = {
+ rail: ['Lorem', 'Ipsum', 'Dolor'],
+ columns: ['Lorem', 'Ipsum', 'Dolor'],
+ figures: ['1,284', '98.2%', '41'],
+ amounts: ['$12,400', '$3,860', '$9,215'],
+ panel: ['Lorem ipsum', 'Dolor sit amet'],
+ switches: ['Lorem ipsum', 'Dolor sit'],
+ chartTitle: 'Lorem ipsum dolor',
+ lanes: ['Lorem', 'Ipsum', 'Dolor', 'Amet', 'Elit'],
+};
+
+const LOREM_DOCS = {
+ rail: ['Lorem ipsum', 'Dolor', 'Consectetur', 'Adipiscing elit'],
+ crumb: 'Lorem / Ipsum dolor',
+ note: 'Nota',
+};
+
+const LOREM_INDEX = {
+ stops: ['Lorem', 'Ipsum', 'Dolor', 'Amet'],
+};
+
/* The desktop artboard sets three cards and the phone two, so a fourth would
be words the agent writes and nobody ever reads. */
const GALLERY_CARDS = 3;
@@ -358,13 +404,14 @@ function fillIndexed(root, selector, values) {
and a board takes the slots its surface has and leaves the rest alone. The
desktop and the phone are filled separately because the indexed slots start
counting again on each. */
-function fillBoard(board, preview, specimen) {
+function fillBoard(board) {
+ const preview = LOREM_PREVIEW;
+ const specimen = LOREM_SPECIMEN;
const desktop = board.querySelector('.ps-desktop');
const phoneBody = board.querySelector('.ps-phone-body');
- const phoneFooter = board.querySelector('.ps-phone-footer');
// A rail means the sections of a document on one board and the areas of a
// tool on the other, so it is the one slot whose words the surface decides.
- const rail = board.dataset.surface === 'read' ? DOCS.rail : APP.rail;
+ const rail = board.dataset.surface === 'read' ? LOREM_DOCS.rail : LOREM_APP.rail;
const fill = (selector, value) => {
for (const node of board.querySelectorAll(selector)) node.textContent = value;
};
@@ -379,11 +426,11 @@ function fillBoard(board, preview, specimen) {
fill('[data-type-section-body]', LOREM.paragraph);
fill('[data-type-section-link]', preview.sectionLink);
fill('[data-type-footer-mark]', preview.footerMark);
- fill('[data-type-note-label]', DOCS.note);
+ fill('[data-type-note-label]', LOREM_DOCS.note);
fill('[data-type-note-body]', LOREM.note);
- fill('[data-type-crumb]', DOCS.crumb);
+ fill('[data-type-crumb]', LOREM_DOCS.crumb);
fill('[data-type-caption]', LOREM.caption);
- fill('[data-type-chart-title]', APP.chartTitle);
+ fill('[data-type-chart-title]', LOREM_APP.chartTitle);
for (const card of [desktop, phoneBody]) {
fillIndexed(card, '[data-type-nav]', preview.nav);
fillIndexed(card, '[data-type-proof]', preview.proof);
@@ -391,27 +438,19 @@ function fillBoard(board, preview, specimen) {
fillIndexed(card, '[data-type-gallery-meta]', preview.gallery.map(({ meta }) => meta));
fillIndexed(card, '[data-type-passage]', LOREM.passages);
fillIndexed(card, '[data-type-item]', LOREM.items);
- fillIndexed(card, '[data-type-stop]', INDEX.stops);
+ fillIndexed(card, '[data-type-stop]', LOREM_INDEX.stops);
fillIndexed(card, '[data-type-rail]', rail);
- fillIndexed(card, '[data-type-lane]', APP.lanes);
- fillIndexed(card, '[data-type-column]', APP.columns);
- fillIndexed(card, '[data-type-figure]', APP.figures);
- fillIndexed(card, '[data-type-amount]', APP.amounts);
- fillIndexed(card, '[data-type-panel]', APP.panel);
- fillIndexed(card, '[data-type-switch]', APP.switches);
+ fillIndexed(card, '[data-type-lane]', LOREM_APP.lanes);
+ fillIndexed(card, '[data-type-column]', LOREM_APP.columns);
+ fillIndexed(card, '[data-type-figure]', LOREM_APP.figures);
+ fillIndexed(card, '[data-type-amount]', LOREM_APP.amounts);
+ fillIndexed(card, '[data-type-panel]', LOREM_APP.panel);
+ fillIndexed(card, '[data-type-switch]', LOREM_APP.switches);
}
fillIndexed(desktop?.querySelector('.ps-footer'), '[data-type-footer-link]', preview.footerLinks);
- fillIndexed(phoneFooter, '[data-type-footer-link]', preview.footerLinks);
}
function syncFontPair(pair) {
- const manifest = fontManifest;
- const preview = {
- ...FALLBACK_FONTS.preview,
- ...manifest.preview,
- ...pair.preview,
- };
- const specimen = { ...manifest.specimen, ...pair.specimen };
// Written once on the stage the boards share, and on screen 05's two preview
// columns, which are set in the pair chosen here so the faces travel with it.
for (const target of [typeStage, scaleSheet, scaleSpecimen]) {
@@ -419,7 +458,7 @@ function syncFontPair(pair) {
target.style.setProperty('--pt-body', fontStack(pair.body.family));
target.style.setProperty('--pt-heading-weight', pair.heading.weight);
}
- for (const board of typeBoards) fillBoard(board, preview, specimen);
+ for (const board of typeBoards) fillBoard(board);
document.querySelector('[name="font-heading"]').value = pair.heading.family;
document.querySelector('[name="font-body"]').value = pair.body.family;
document.querySelector('[name="font-heading-source"]').value = pair.heading.source || '';
diff --git a/picker/styles/picker.css b/picker/styles/picker.css
index 4ed1b418f..4ef7aad4a 100644
--- a/picker/styles/picker.css
+++ b/picker/styles/picker.css
@@ -2723,54 +2723,15 @@ body.picker-page {
grid with the buttons underneath it and leaves this one 90px short of what it
now owns. */
.picker-screen[data-screen="03"] .picker-strategy-grid {
- --pk-fit: calc(100svh - var(--pk-chrome, 250px));
- max-height: var(--pk-fit);
- grid-template-rows: minmax(0, 1fr) auto;
- row-gap: 14px;
+ max-height: calc(100svh - var(--pk-chrome, 346px));
}
.picker-screen[data-screen="03"] .picker-strategy-grid > .picker-type-rail {
- grid-row: 1 / -1;
- grid-template-rows: subgrid;
- /* The rail is measured against the viewport rather than against the frame
- beside it. The frame draws the chosen surface at that drawing's own ratio,
- which is wider than the artboard this column used to hold, so matching its
- height would spend the whole column on four rows of 78px.
-
- The band no longer has to give on a short viewport: the row it sits in is
- shared with the CTA stack, which is 90px whatever the viewport does, so
- anything the band gave back would be spent on empty space beside the
- buttons. */
- --pk-band: 96px;
+ height: auto;
+ align-self: start;
+ grid-template-rows: auto auto auto;
}
-/* These four rows are what the top row of the screen measures, and the frame
- beside them takes whatever they come to, so this is also where the drawing's
- height is decided.
-
- Floored at 88px, which is the tallest option's two lines plus the air they
- need to read as a paragraph rather than a block. Below that the row has no
- padding left to give and the sentence is what gets cut, so past the floor the
- panel is allowed to run past the budget and scroll instead. */
-.picker-screen[data-screen="03"] .picker-strategy-choices.picker-type-options {
- /* The row formula below is the only cap this panel needs. The shared one
- measures against the column budget alone, which on a short viewport asks
- for less than the floor and clips the fourth option to reach it. */
- max-height: none;
- /* The row is the panel's own height at every size the budget clears, so
- filling it costs nothing there and buys the scroll on the sizes where the
- four rows have stopped fitting. */
- align-self: stretch;
- /* The 16 the rows do not get is the row the palette and the buttons share,
- less the grid's own row gap and the panel's hairline. */
- grid-auto-rows: max(88px, min(108px, calc((var(--pk-fit) - var(--pk-band) - 16px) / 4)));
-}
-
-/* Equal rows, sized by the tallest one's copy rather than by how many there
- are. Stretching the tracks to the artboard's height instead makes a row on a
- three-option screen half again as tall as the same row on a four-option one,
- and the difference is spent on empty space under two lines of text. The
- panel hugs the rows it has, so nothing draws an empty band underneath. */
.picker-strategy-choices.picker-type-options {
align-self: start;
max-height: var(--pk-column);
@@ -2960,25 +2921,9 @@ body.picker-page {
hold either way. Persuade is still drawn in pixels and sits loose in a frame
this size.
============================================================ */
-.picker-strategy-subgrid {
- min-width: 0;
- grid-row: 1 / -1;
- display: grid;
- grid-template-rows: subgrid;
-}
-
-/* Centred on the frame rather than on the page, which is where the question was
- answered. The row is sized for the palette across from it and the buttons come
- to a few pixels less, so they take the middle of it. */
-.picker-strategy-subgrid > .picker-actions-stack {
- align-content: center;
-}
-
-/* The stage is the frame's own box plus the strip over it: a row for the tab
- strip and a row for the frame, so the strip's height is room the layout
- reserved rather than room taken off the question above. */
.picker-strategy-stage {
min-width: 0;
+ min-height: 0;
display: grid;
grid-template-rows: auto minmax(0, 1fr);
}
@@ -2992,6 +2937,8 @@ body.picker-page {
/* The frame runs down to the bottom of the choices beside it, so it takes the
row's height rather than the 16 / 7 it carries everywhere else. */
aspect-ratio: auto;
+ width: 100%;
+ height: 100%;
}
/* The tiles and the palette screen show the drawing at a fraction of this
@@ -4381,8 +4328,8 @@ body.picker-page {
heading is the wide one. Both are counted in the base step, so the cadence
holds while every size in the column moves. */
gap: calc(var(--sp-rhythm) * 1.5);
- padding-block: clamp(14px, 2.4%, 28px);
- padding-inline: calc(var(--sp-rail) + var(--sp-rail-gap) + 4px) 16px;
+ padding-block: calc(clamp(14px, 2.4%, 28px) + 10px) clamp(14px, 2.4%, 28px);
+ padding-inline: calc(var(--sp-rail) + var(--sp-rail-gap) + 8px) 16px;
background: var(--ks-lacquer-raised);
color: var(--ks-text);
border: 1px solid var(--ks-rule);
@@ -5221,6 +5168,7 @@ body.picker-page {
.picker-preview-type .ps-phone {
--ps-gutter: 6%;
+ grid-template-rows: 7.2% 1fr;
}
/* On a structural board the band inset is the drawn field's own margin, and it is
@@ -5268,7 +5216,7 @@ body.picker-page {
/* The pair is the subject and the image is a placeholder for one, so the copy
takes the column and the image takes what it needs to read as a picture. */
.picker-preview-type .ps-hero {
- grid-template-columns: minmax(0, 1fr) 26%;
+ grid-template-columns: minmax(0, 1fr) 34%;
gap: var(--ps-gap-lg);
padding: var(--ps-band-y) var(--ps-gutter);
}
@@ -5300,7 +5248,7 @@ body.picker-page {
what centers in the band, so a pair that sets a shorter title does not leave
the whole section sitting against the rule above it. */
.picker-preview-type .ps-editorial {
- grid-template-columns: minmax(0, 1fr) 38%;
+ grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
gap: var(--ps-gap-lg);
align-content: center;
align-items: start;
@@ -5315,6 +5263,16 @@ body.picker-page {
height: auto;
grid-template-columns: repeat(3, minmax(0, 1fr));
gap: var(--ps-gap-md);
+ justify-items: center;
+}
+
+.picker-preview-type .ps-desktop .ps-gallery-item {
+ justify-items: center;
+ text-align: center;
+}
+
+.picker-preview-type .ps-desktop .ps-gallery-item span {
+ align-items: center;
}
/* The thumbnail stands in for a picture, not for the band: left to fill the
@@ -5332,6 +5290,10 @@ body.picker-page {
aspect-ratio: 1;
}
+.picker-preview-type .ps-desktop .ps-gallery-item > i {
+ margin-inline: auto;
+}
+
/* Words set taller than bars, and the phone is the narrowest frame they have
to fit. Its card row goes: nav, hero, proof and a section of running copy
already show every face at both sizes, and the row that was left over is
@@ -5359,6 +5321,65 @@ body.picker-page {
.picker-preview-type[data-surface="persuade"] .ps-phone-body {
grid-template-rows: repeat(5, auto);
+ gap: 0;
+ align-content: start;
+}
+
+.picker-preview-type[data-surface="persuade"] .ps-phone-body .pt-headline {
+ font-size: 26px;
+ line-height: 1.15;
+ margin-block-end: 8px;
+}
+
+.picker-preview-type[data-surface="persuade"] .ps-phone-body .pt-body {
+ margin-block-end: var(--ps-gap-md);
+}
+
+.picker-preview-type[data-surface="persuade"] .ps-phone-body .ps-actions {
+ margin-block-end: var(--ps-gap-lg);
+}
+
+.picker-preview-type[data-surface="persuade"] .ps-phone-body .ps-proof {
+ grid-template-columns: auto minmax(0, 1fr) auto;
+ align-items: center;
+ column-gap: var(--ps-gap-md);
+ margin-block-end: var(--ps-gap-md);
+}
+
+.picker-preview-type[data-surface="persuade"] .ps-phone-body .ps-proof-divider,
+.picker-preview-type[data-surface="persuade"] .ps-phone-body .ps-proof-item:nth-of-type(2) {
+ display: none;
+}
+
+.picker-preview-type[data-surface="persuade"] .ps-phone-body .ps-proof-item:first-of-type {
+ grid-column: 2;
+ justify-content: center;
+}
+
+.picker-preview-type[data-surface="persuade"] .ps-phone-body .ps-proof::before,
+.picker-preview-type[data-surface="persuade"] .ps-phone-body .ps-proof::after {
+ content: "";
+ position: static;
+ width: 5px;
+ height: 5px;
+ background: none;
+ border-left: 1px solid color-mix(in oklab, var(--pvs-bars) 38%, transparent);
+ border-bottom: 1px solid color-mix(in oklab, var(--pvs-bars) 38%, transparent);
+ align-self: center;
+}
+
+.picker-preview-type[data-surface="persuade"] .ps-phone-body .ps-proof::before {
+ grid-column: 1;
+ transform: rotate(45deg);
+}
+
+.picker-preview-type[data-surface="persuade"] .ps-phone-body .ps-proof::after {
+ grid-column: 3;
+ transform: rotate(-135deg);
+}
+
+.picker-preview-type[data-surface="persuade"] .ps-phone-body .ps-editorial-copy {
+ gap: var(--ps-gap-xs);
}
/* One gap owns the spacing down the phone. The margins underneath it were a
@@ -5736,7 +5757,9 @@ body.picker-page {
}
.picker-preview-type .ps-gallery-item span {
- gap: var(--ps-gap-xs);
+ display: flex;
+ flex-direction: column;
+ gap: 4px;
}
/* Card labels wrap instead of truncating: a two-line label still reads, and a
@@ -5745,10 +5768,18 @@ body.picker-page {
overflow: visible;
color: var(--pvs-bars);
white-space: normal;
+ text-box: unset;
+ display: block;
}
-.picker-preview-type .ps-gallery-item b:first-child {
+.picker-preview-type .ps-gallery-item b:first-child,
+.picker-preview-type .ps-gallery-item [data-type-gallery-title] {
color: var(--pvs-title);
+ line-height: 1.38;
+}
+
+.picker-preview-type .ps-gallery-item b:last-child {
+ line-height: 1.45;
}
/* ============================================================