From 55617ac5d8d048cfb42c2bd7d763683e5f23f0c8 Mon Sep 17 00:00:00 2001 From: Abdul Wahab Date: Tue, 11 Aug 2026 17:20:40 +0500 Subject: [PATCH] update --- picker/scripts/design-context.js | 121 ++++++++-- picker/styles/design-context.css | 389 +++++++++++++++++++++++++++++++ picker/styles/picker.css | 20 +- 3 files changed, 508 insertions(+), 22 deletions(-) diff --git a/picker/scripts/design-context.js b/picker/scripts/design-context.js index ed2bdac69..8f502a1a9 100644 --- a/picker/scripts/design-context.js +++ b/picker/scripts/design-context.js @@ -235,7 +235,7 @@ function paintCommitted(node) { /* Clone one questionnaire drawing into a dcx frame. Inline styles travel with the clone; ids do not (they would collide with the originals). */ -function proofHtml(source, { strategy = '', kind = 'board' } = {}) { +function proofHtml(source, { strategy = '', kind = 'board', marks = null } = {}) { if (!source) return ''; const clone = source.cloneNode(true); clone.hidden = false; @@ -249,6 +249,15 @@ function proofHtml(source, { strategy = '', kind = 'board' } = {}) { wrap.className = `dcx-proof dcx-proof--${kind}`; wrap.setAttribute('aria-hidden', 'true'); if (strategy) wrap.dataset.dcxStrategy = strategy; + /* Committed structural answers, restated on the frame. On the screens they + reach a carried artboard through checked inputs inside #picker-form, + which a clone in the document is outside of, so design-context.css + mirrors those bodies against these attributes instead. */ + if (marks) { + for (const [key, value] of Object.entries(marks)) { + if (value) wrap.setAttribute(`data-dcx-${key}`, value); + } + } paintCommitted(wrap); wrap.appendChild(clone); return wrap.outerHTML; @@ -261,6 +270,22 @@ const surfaceBoard = (mode) => $(`[data-surface-stage] [data-surface="${mode}"]` const surfaceTilePreview = (mode) => $(`input[name="surface-modes"][value="${mode}"]`) ?.closest('.picker-mode-tile')?.querySelector('.picker-preview'); +/* The boundaries screen keeps one carried ps artboard per surface, and by + that screen the drawing is the page as chosen so far. It is the clone + source for any proof that wants the whole material story on one page. */ +const carriedBoard = (mode) => $(`[data-question="boundaries"] .picker-artboard[data-surface="${mode}"]`); + +/* One surface's committed structural answers, as the data-dcx-* marks the + document stylesheet keys its mirrored bodies on. Layout is one answer for + the whole run, so every surface's frame carries the same value. */ +const materialMarks = (s, mode) => ({ + surface: mode, + boundary: s.boundaries.find((entry) => entry.mode === mode)?.value || '', + corner: s.corners.find((entry) => entry.mode === mode)?.value || '', + depth: s.depth.find((entry) => entry.mode === mode)?.value || '', + layout: s.layout.value || '', +}); + /* One line per surface for the per-surface questions, marking whether the user configured the surface or it kept the default for its kind. */ const surfaceDefs = (entries) => defs(entries.map((entry) => ({ @@ -510,15 +535,27 @@ function buildTypography(s, name) { function buildIconography(s, name) { const parts = [heading(6, 'Iconography', 'Icon library, license, where it lives.', name)]; if (s.icons.pack) { - const sheet = proofHtml($('[data-icon-sheet]'), { kind: 'icons' }); + /* The glyphs are fetched when screen 11 first opens, so a fast run can + reach the document before any landed, and a failed fetch leaves only + an error line. A sheet with no icon cells proves nothing about the + hand, so it is dropped rather than framed. */ + const sheetSource = $('[data-icon-sheet]'); + const sheet = sheetSource?.querySelector('.picker-icon-cell') ? proofHtml(sheetSource, { kind: 'icons' }) : ''; if (sheet) { parts.push(block('The hand', sheet + note(`${escapeHtml(s.icons.pack)}’s canonical set, as the icons screen previewed it. One pack, one hand: no mixed sets.`))); } + /* The chosen radio's own row copy: the character note and the grid, + stroke, and license summary the screen showed beside the name. Read + off the DOM rather than kept twice, the optionCopy convention. */ + const packLabel = form.querySelector('input[name="icon-pack"]:checked')?.closest('label'); + const packNote = packLabel?.querySelector('.picker-strategy-desc')?.textContent.trim() || ''; + const packMeta = packLabel?.querySelector('.picker-icon-meta')?.textContent.trim() || ''; parts.push(block('Library', defs([ - { dt: 'Pack', dd: `${escapeHtml(s.icons.pack)}` }, - s.icons.license && { dt: 'License', dd: escapeHtml(s.icons.license) }, - s.icons.url && { dt: 'Home', dd: `${escapeHtml(s.icons.url)}` }, + { dt: 'Pack', dd: `${escapeHtml(s.icons.pack)}${packMeta ? ` · ${escapeHtml(packMeta)}` : ''}` }, + packNote ? { dt: 'Why this hand', dd: escapeHtml(packNote) } : null, + s.icons.license ? { dt: 'License', dd: escapeHtml(s.icons.license) } : null, + s.icons.url ? { dt: 'Home', dd: `${escapeHtml(s.icons.url)}` } : null, ].filter(Boolean)) + note('Chosen on the icons screen. The pack names the hand; stroke weight and metaphor rules resolve during implementation.'))); } else { parts.push(block('Library', empty('No pack selected', 'The icons screen was not completed on this run.'))); @@ -538,12 +575,35 @@ const pickGrid = (entries) => `
+ ${proofHtml(board, { + strategy: s.strategy.find((entry) => entry.mode === surface.mode)?.value || '', + kind: 'board', + marks: materialMarks(s, surface.mode), + })} +
+

${escapeHtml(surface.label)}

+
+ `; + }).filter(Boolean); + if (proofCards.length) { + parts.push(block('The page, as chosen', `
${proofCards.join('')}
` + + note('Each surface’s page anatomy carrying every structural answer below at once, the way the question screens accumulated them: color strategy, layout, boundaries, corners, depth.'))); + } /* Movement is only asked of the two surfaces that make a claim on attention, so this list is one or two entries long and empty on a run of neither. An empty one says the question was never put, which is a different thing from a quiet answer and is worth saying out loud. */ if (s.motion.length) { - parts.push(block('Motion per surface', surfaceDefs(s.motion) + parts.push(block('Motion per surface', pickGrid(s.motion) + note(interview.motionEnergy ? `The seed interview asked for ${escapeHtml(interview.motionEnergy)}; the motion screen answered it per surface above.` : 'Asked of the landing page and the portfolio only. A tool and a document are moved through rather than watched, so their movement follows the interface rather than a house style.'))); @@ -571,22 +631,47 @@ function buildMaterial(s, name) { function buildInterface(s, name) { const parts = [heading(8, 'Interface', 'Per-surface decisions at a glance, component status.', name)]; - const ASPECTS = [['Color strategy', 'strategy'], ['Boundaries', 'boundaries'], ['Corners', 'corners'], ['Depth', 'depth']]; - parts.push(block('Decisions per surface', `
${s.surfaces.map((surface) => ` + parts.push(block('Decisions per surface', `
${s.surfaces.map((surface) => { + const strategyValue = s.strategy.find((entry) => entry.mode === surface.mode)?.value || ''; + const board = carriedBoard(surface.mode); + /* The matrix quotes every per-surface answer. A question this surface + was never asked reads Not asked rather than borrowing another + surface's answer; layout is one answer for the run and is quoted on + every card, the rule the Material page states. */ + const rows = [ + ['Color strategy', s.strategy.find((entry) => entry.mode === surface.mode)], + ['Boundaries', s.boundaries.find((entry) => entry.mode === surface.mode)], + ['Corners', s.corners.find((entry) => entry.mode === surface.mode)], + ['Depth', s.depth.find((entry) => entry.mode === surface.mode)], + ['Motion', s.motion.find((entry) => entry.mode === surface.mode)], + ['Layout', s.layout.value ? s.layout : undefined], + ]; + return `
- ${proofHtml(surfaceBoard(surface.mode) || surfaceTilePreview(surface.mode), { - strategy: s.strategy.find((entry) => entry.mode === surface.mode)?.value || '', - kind: 'board', - })} + ${board + ? proofHtml(board, { strategy: strategyValue, kind: 'board', marks: materialMarks(s, surface.mode) }) + : proofHtml(surfaceBoard(surface.mode) || surfaceTilePreview(surface.mode), { strategy: strategyValue, kind: 'board' })}

${escapeHtml(surface.label)}

-
${ASPECTS.map(([label, key]) => { - const entry = s[key].find((item) => item.mode === surface.mode); - return `
${escapeHtml(label)}
${escapeHtml(entry?.title || '—')}${entry && !entry.chosen ? ' default' : ''}
`; - }).join('')}
+
${rows.map(([label, entry]) => ` +
${escapeHtml(label)}
${entry ? escapeHtml(entry.title) : 'Not asked'}${entry && !entry.chosen ? ' default' : ''}
`).join('')}
-
`).join('')}
` - + note('Each surface’s artboard in its own color strategy, with the four per-surface answers beneath it.'))); + `; + }).join('')}
` + + note('Each surface’s anatomy carrying its committed answers, with every per-surface decision beneath it.'))); + /* The run's own tokens in one place: what the seed DESIGN.md frontmatter + will carry. Every row omits when its screen was not completed. */ + const kit = [ + s.fonts.heading ? { dt: 'Faces', dd: `${escapeHtml(s.fonts.heading)} for headings, ${escapeHtml(s.fonts.body)} for body` } : null, + s.scale.ratio ? { dt: 'Type scale', dd: `${escapeHtml(s.scale.name)} · ratio ${s.scale.ratio.toFixed(3)} on a 16px base` } : null, + s.icons.pack ? { dt: 'Icons', dd: `${escapeHtml(s.icons.pack)}${s.icons.license ? ` · ${escapeHtml(s.icons.license)}` : ''}` } : null, + s.palette.length ? { dt: 'Palette', dd: s.palette.map((entry) => `${entry.hex}`).join(' · ') } : null, + s.layout.value ? { dt: 'Layout', dd: `${escapeHtml(s.layout.title)}, one answer for the run` } : null, + ].filter(Boolean); + if (kit.length) { + parts.push(block('The kit', defs(kit) + + note('The tokens the seed DESIGN.md will carry in its frontmatter, gathered from their own pages in this document.'))); + } parts.push(block('Components', empty( 'No component library seeded yet', 'Components are documented on the first scan pass, once there is code to capture actual tokens and states from. Re-run /impeccable document then.', diff --git a/picker/styles/design-context.css b/picker/styles/design-context.css index 5b7cf19ce..9fea15df9 100644 --- a/picker/styles/design-context.css +++ b/picker/styles/design-context.css @@ -1189,6 +1189,395 @@ body.dcx-open { overflow: hidden; background: linear-gradient(180deg, var(--ks-l --pv-tertiary: var(--pkc-tertiary); --pv-t-on-n: var(--pkc-t-on-p); } +/* ============================================================ + Material proofs: the structural screens' own artboards, cloned. + + A .dcx-proof--board can also frame a ps artboard clone (the anatomy + screens 07 to 10 draw on), not just a tile drawing. On screen those + boards take every committed answer through checked inputs inside + #picker-form, which a clone in the document is outside of, so the frame + restates each answer as a data-dcx-* attribute and the bodies below are + verbatim copies of the committed bodies the screens set. Change a body + here and in its named source together. The palette rides two ways: the + screens paint all thirteen --pv-* slots inline on every artboard they + showed (inline styles travel with a clone), and for a board whose screen + the run never opened, the frame's --pkc-* paint reaches the clone + through the same six-slot map the tile clones above use, with the + artboard's own class defaults covering the contrast slots. */ +.dcx-proof--board > .picker-artboard { + --pv-primary: var(--pkc-primary, var(--ks-champagne)); + --pv-secondary: var(--pkc-secondary, var(--ks-patina)); + --pv-tertiary: var(--pkc-tertiary, var(--ks-kinpaku)); + --pv-neutral: var(--pkc-neutral, var(--ks-lacquer-raised)); + --pv-n-ink: var(--pkc-n-ink, var(--ks-champagne)); + --pv-p-ink: var(--pkc-p-ink, var(--ks-champagne)); +} + +/* Two rules the clone loses with its data-surface attribute (proofHtml + strips it): the landing board's right-gutter chrome, and the handset + print's freeform cut, which rides --pvs-drift and stays a rectangle + under the other layout answers. The frame's data-dcx-surface carries + the surface instead. Sources: picker/styles/screens/layout.css, the + [data-carry][data-surface="persuade"] rules. */ +.dcx-proof--board[data-dcx-surface="persuade"] > .picker-artboard :is(.ps-nav, .ps-editorial, .ps-footer) { + padding-right: var(--pvs-gutter-end); +} + +.dcx-proof--board[data-dcx-surface="persuade"] > .picker-artboard .ps-phone-body > .ps-image { + clip-path: polygon(0 0, 100% 0, 100% calc(100% - var(--pvs-drift, 0) * 16%), 0 100%); +} + +/* The strategy, restated for artboard clones: the [data-artboard] bodies + from picker.css. Restrained is the artboard's own defaults there and + stays bodiless here, exactly as the tile remaps above leave full + palette alone. */ +.dcx-proof--board[data-dcx-strategy="committed"] > .picker-artboard { + --pvs-headline: color-mix(in oklab, var(--pv-primary) 80%, var(--pv-strong)); + --pvs-headline-text: var(--pv-p-on-n); + --pvs-eyebrow: var(--pv-primary); + --pvs-ghost: color-mix(in oklab, var(--pv-primary) 14%, var(--pv-neutral)); + --pvs-ghost-edge: var(--pv-primary); + --pvs-image: var(--pv-primary); + --pvs-image-a: var(--pv-primary); + --pvs-image-b: color-mix(in oklab, var(--pv-primary) 72%, var(--pv-neutral)); + --pvs-image-edge: var(--pv-primary); + --pvs-accent-a: var(--pv-primary); + --pvs-accent-b: color-mix(in oklab, var(--pv-primary) 70%, var(--pv-neutral)); + --pvs-accent-c: var(--pv-primary); + --pvs-accent-d: color-mix(in oklab, var(--pv-primary) 18%, var(--pv-neutral)); +} + +.dcx-proof--board[data-dcx-strategy="full-palette"] > .picker-artboard { + --pvs-headline: color-mix(in oklab, var(--pv-primary) 80%, var(--pv-strong)); + --pvs-headline-text: var(--pv-p-on-n); + --pvs-accent-text: var(--pv-t-on-n); + --pvs-eyebrow: var(--pv-tertiary); + --pvs-ghost: color-mix(in oklab, var(--pv-secondary) 18%, var(--pv-neutral)); + --pvs-ghost-edge: var(--pv-secondary); + --pvs-image: var(--pv-primary); + --pvs-image-a: var(--pv-primary); + --pvs-image-b: color-mix(in oklab, var(--pv-secondary) 32%, var(--pv-primary)); + --pvs-image-edge: var(--pv-primary); + --pvs-signal: var(--pv-tertiary); + --pvs-signal-ink: var(--pv-t-ink); + --pvs-signal-text: var(--pv-t-on-t); + --pvs-accent-a: var(--pv-secondary); + --pvs-accent-b: color-mix(in oklab, var(--pv-secondary) 42%, var(--pv-neutral)); + --pvs-accent-c: var(--pv-primary); + --pvs-accent-d: var(--pv-tertiary); +} + +.dcx-proof--board[data-dcx-strategy="drenched"] > .picker-artboard { + --pvs-ground: var(--pv-primary); + --pvs-ink: var(--pv-p-ink); + --pvs-surface: color-mix(in oklab, var(--pv-p-ink) 10%, var(--pv-primary)); + --pvs-headline: var(--pv-p-ink); + --pvs-eyebrow: color-mix(in oklab, var(--pv-p-ink) 70%, var(--pv-primary)); + --pvs-copy: color-mix(in oklab, var(--pv-p-ink) 55%, var(--pv-primary)); + --pvs-title: var(--pv-p-ink); + --pvs-cta: var(--pv-p-ink); + --pvs-cta-ink: var(--pv-primary); + --pvs-cta-text: var(--pv-p-on-i); + --pvs-mark-text: var(--pv-p-ink); + --pvs-accent-text: var(--pv-t-on-p); + --pvs-copy-mix: 14%; + --pvs-bars-mix: 16%; + --pvs-ghost: color-mix(in oklab, var(--pv-p-ink) 22%, var(--pv-primary)); + --pvs-ghost-edge: color-mix(in oklab, var(--pv-p-ink) 45%, var(--pv-primary)); + --pvs-image: color-mix(in oklab, var(--pv-p-ink) 20%, var(--pv-primary)); + --pvs-image-a: color-mix(in oklab, var(--pv-p-ink) 16%, var(--pv-primary)); + --pvs-image-b: color-mix(in oklab, var(--pv-p-ink) 28%, var(--pv-primary)); + --pvs-image-edge: color-mix(in oklab, var(--pv-p-ink) 40%, var(--pv-primary)); + --pvs-signal: var(--pv-tertiary); + --pvs-signal-ink: var(--pv-t-ink); + --pvs-signal-text: var(--pv-t-on-t); + --pvs-bars: color-mix(in oklab, var(--pv-p-ink) 45%, var(--pv-primary)); + --pvs-rule: color-mix(in oklab, var(--pv-p-ink) 28%, var(--pv-primary)); + --pvs-accent-a: var(--pv-secondary); + --pvs-accent-b: var(--pv-tertiary); + --pvs-accent-c: color-mix(in oklab, var(--pv-p-ink) 30%, var(--pv-primary)); + --pvs-accent-d: color-mix(in oklab, var(--pv-p-ink) 14%, var(--pv-primary)); +} + +/* Boundaries: the four committed bodies from styles/screens/boundaries.css. */ +.dcx-proof--board[data-dcx-boundary="open-space"] > .picker-artboard { + --pvs-divider-w: 0px; + --pvs-band: transparent; + --pvs-band-alt: transparent; + --pvs-band-top: transparent; + --pvs-panel: transparent; + --pvs-panel-edge-w: 0px; + --pvs-panel-pad: 0px; + --pvs-proof-inset: 0px; +} + +.dcx-proof--board[data-dcx-boundary="thin-dividers"] > .picker-artboard { + --pvs-divider-w: 1px; + --pvs-divider-c: color-mix(in oklab, var(--pvs-ink) 24%, var(--pvs-ground)); + --pvs-band: transparent; + --pvs-band-alt: transparent; + --pvs-band-top: transparent; + --pvs-panel: transparent; + --pvs-panel-edge-w: 0px; + --pvs-panel-pad: 0px; + --pvs-proof-inset: 0px; +} + +.dcx-proof--board[data-dcx-boundary="surface-changes"] > .picker-artboard { + --pvs-divider-w: 0px; + --pvs-band: color-mix(in oklab, var(--pvs-ink) 7%, var(--pvs-ground)); + --pvs-band-alt: color-mix(in oklab, var(--pvs-ink) 13%, var(--pvs-ground)); + --pvs-band-top: color-mix(in oklab, var(--pvs-ink) 7%, var(--pvs-ground)); + --pvs-panel: transparent; + --pvs-panel-edge-w: 0px; + --pvs-panel-pad: 0px; + --pvs-proof-inset: 0px; +} + +.dcx-proof--board[data-dcx-boundary="cards-and-panels"] > .picker-artboard { + --pvs-divider-w: 0px; + --pvs-band: transparent; + --pvs-band-alt: color-mix(in oklab, var(--pvs-ink) 5%, var(--pvs-ground)); + --pvs-band-top: transparent; + --pvs-panel: color-mix(in oklab, var(--pvs-ink) 5%, var(--pvs-ground)); + --pvs-panel-edge: color-mix(in oklab, var(--pvs-ink) 20%, var(--pvs-ground)); + --pvs-panel-edge-w: 1px; + --pvs-panel-pad: 5%; + --pvs-proof-inset: var(--pvs-gutter); +} + +/* The open rail plate joins the card answer, as on the screen. */ +.dcx-proof--board[data-dcx-boundary="cards-and-panels"] > .picker-artboard .ps-ops-item { + background-color: var(--pvs-panel); +} + +/* Corners: the four committed bodies from styles/screens/corners.css. */ +.dcx-proof--board[data-dcx-corner="sharp"] > .picker-artboard { + --pvs-radius-frame: 0px; + --pvs-radius-frame-phone: 0px; + --pvs-radius-surface: 0px; + --pvs-radius-control: 0px; + --pvs-radius-bar: 0px; +} + +.dcx-proof--board[data-dcx-corner="slightly-soft"] > .picker-artboard { + --pvs-radius-frame: 4px; + --pvs-radius-frame-phone: 5px; + --pvs-radius-surface: 3px; + --pvs-radius-control: 3px; + --pvs-radius-bar: 2px; +} + +.dcx-proof--board[data-dcx-corner="friendly"] > .picker-artboard { + --pvs-radius-frame: 7px; + --pvs-radius-frame-phone: 11px; + --pvs-radius-surface: 8px; + --pvs-radius-control: 8px; + --pvs-radius-bar: 3px; +} + +.dcx-proof--board[data-dcx-corner="pill"] > .picker-artboard { + --pvs-radius-frame: 9px; + --pvs-radius-frame-phone: 15px; + --pvs-radius-surface: 12px; + --pvs-radius-control: 999px; + --pvs-radius-bar: 3px; +} + +/* Depth: the three committed bodies from styles/screens/depth.css. */ +.dcx-proof--board[data-dcx-depth="flat"] > .picker-artboard { + --pvs-shadow-chrome: none; + --pvs-shadow-card: none; + --pvs-shadow-control: none; + --pvs-shadow-surface: none; +} + +.dcx-proof--board[data-dcx-depth="soft-lift"] > .picker-artboard { + --pvs-shadow-chrome: 0 1px 2px rgb(0 0 0 / 0.1); + --pvs-shadow-card: + 0 1px 1px rgb(0 0 0 / 0.15), + 0 3px 7px rgb(0 0 0 / 0.14); + --pvs-shadow-control: 0 1px 2px rgb(0 0 0 / 0.24); + --pvs-shadow-surface: 0 2px 5px rgb(0 0 0 / 0.14); +} + +.dcx-proof--board[data-dcx-depth="floating"] > .picker-artboard { + --pvs-shadow-chrome: 0 2px 6px rgb(0 0 0 / 0.16); + --pvs-shadow-card: + 0 2px 3px rgb(0 0 0 / 0.2), + 0 9px 18px rgb(0 0 0 / 0.24); + --pvs-shadow-control: 0 3px 6px rgb(0 0 0 / 0.32); + --pvs-shadow-surface: 0 6px 14px rgb(0 0 0 / 0.22); +} + +/* Where a cast shadow is allowed to land, keyed to the boundary answer + exactly as depth.css keys it to the checked boundary input. */ +.dcx-proof--board[data-dcx-boundary="cards-and-panels"] > .picker-artboard :is(.ps-gallery-item, .ps-desktop > .ps-proof), +.dcx-proof--board[data-dcx-boundary="surface-changes"] > .picker-artboard .ps-desktop > .ps-proof { + box-shadow: var(--pvs-shadow-card); +} + +.dcx-proof--board:not([data-dcx-boundary="cards-and-panels"]) > .picker-artboard .ps-gallery-item { + box-shadow: none; +} + +.dcx-proof--board:not([data-dcx-boundary="cards-and-panels"]) > .picker-artboard .ps-gallery-item > i { + box-shadow: var(--pvs-shadow-card); +} + +.dcx-proof--board:not([data-dcx-boundary="surface-changes"]) > .picker-artboard :is(.ps-nav, .ps-phone-top) { + box-shadow: none; +} + +.dcx-proof--board:not([data-dcx-boundary="surface-changes"]) > .picker-artboard :is(.ps-ops-rail, .ps-docs-rail) { + box-shadow: none; +} + +.dcx-proof--board:not([data-dcx-boundary="surface-changes"]):not([data-dcx-boundary="cards-and-panels"]) > .picker-artboard .ps-ops-panel { + box-shadow: none; +} + +.dcx-proof--board:not([data-dcx-boundary="cards-and-panels"]) > .picker-artboard :is(.ps-ops-chart, .ps-ops-table) { + box-shadow: none; +} + +.dcx-proof--board:not([data-dcx-boundary="cards-and-panels"]) > .picker-artboard .ps-ops-plot > i { + box-shadow: var(--pvs-shadow-card); +} + +.dcx-proof--board:not([data-dcx-boundary="surface-changes"]) > .picker-artboard .ps-docs-note { + box-shadow: none; +} + +.dcx-proof--board[data-dcx-boundary="surface-changes"] > .picker-artboard .ps-index-row--flip { + box-shadow: var(--pvs-shadow-card); +} + +/* Layout: the committed bodies from styles/screens/layout.css, the landing + measure and the region tracks folded into one body per answer (their + sources are two rules on the same committed selector). */ +.dcx-proof--board[data-dcx-layout="simple-grid"] > .picker-artboard { + --pvs-gutter: 6%; + --pvs-gutter-end: 6%; + --pvs-hero-cols: var(--pvs-w6) minmax(0, 1fr); + --pvs-hero-gap: var(--pvs-gut); + --pvs-editorial-cols: var(--pvs-w4) minmax(0, 1fr); + --pvs-editorial-gap: var(--pvs-gut); + --pvs-gallery-cols: repeat(4, minmax(0, 1fr)); + --pvs-gallery-gap: calc(var(--pvs-gut) * 100 / 66.1333); + --pvs-section-align: start; + --pvs-rows: 9.4% 45.5% 9% 27.8% 8.3%; + --pvs-phone-gutter: 7%; + --pvs-phone-gallery-cols: 1fr 1fr; + --pvs-shell-cols: + calc(var(--pvs-w2) + var(--pvs-gut) / 2) + calc(var(--pvs-w7) + var(--pvs-gut)) + minmax(0, 1fr); + --pvs-measure-cols: + calc(var(--pvs-w3) + var(--pvs-gut) / 2) + minmax(0, 1fr); + --pvs-metric-cols: repeat(3, minmax(0, 1fr)); + --pvs-entry-cols: var(--pvs-w6) minmax(0, 1fr); + --pvs-entry-flip-cols: var(--pvs-w6) minmax(0, 1fr); +} + +.dcx-proof--board[data-dcx-layout="simple-grid"] > .picker-artboard .ps-index-row--flip > .ps-image { + grid-area: 1 / 1; +} + +.dcx-proof--board[data-dcx-layout="simple-grid"] > .picker-artboard .ps-index-row--flip > .ps-index-cap { + grid-area: 1 / 2; +} + +.dcx-proof--board[data-dcx-layout="balanced"] > .picker-artboard { + --pvs-gutter: 6%; + --pvs-gutter-end: 6%; + --pvs-hero-cols: var(--pvs-w5) minmax(0, 1fr); + --pvs-hero-gap: var(--pvs-gut); + --pvs-editorial-cols: var(--pvs-w3) minmax(0, 1fr); + --pvs-editorial-gap: var(--pvs-gut); + --pvs-gallery-cols: 23.8fr 15.3333fr 15.3333fr 15.3333fr; + --pvs-gallery-gap: calc(var(--pvs-gut) * 100 / 74.6); + --pvs-section-align: center; + --pvs-rows: 9.4% 50.6% 9% 22.7% 8.3%; + --pvs-phone-gutter: 6%; + --pvs-phone-gallery-cols: 1.35fr 0.85fr; + --pvs-shell-cols: + calc(var(--pvs-w2) + var(--pvs-gut) / 2) + calc(var(--pvs-w8) + var(--pvs-gut)) + minmax(0, 1fr); + --pvs-measure-cols: + calc(var(--pvs-w3) + var(--pvs-gut) / 2) + calc(var(--pvs-w6) + var(--pvs-gut)) + minmax(0, 1fr); + --pvs-metric-cols: 1.45fr 1fr 1fr; + --pvs-entry-cols: var(--pvs-w7) minmax(0, 1fr); + --pvs-entry-flip-cols: minmax(0, 1fr) var(--pvs-w7); +} + +.dcx-proof--board[data-dcx-layout="freeform"] > .picker-artboard { + --pvs-gutter: 6%; + --pvs-gutter-end: 6%; + --pvs-hero-cols: var(--pvs-w5) minmax(0, 1fr); + --pvs-hero-gap: var(--pvs-gut); + --pvs-editorial-cols: var(--pvs-w3) minmax(0, 1fr); + --pvs-editorial-gap: var(--pvs-gut); + --pvs-gallery-cols: repeat(4, minmax(0, 1fr)); + --pvs-gallery-gap: calc(var(--pvs-gut) * 100 / 74.6); + --pvs-section-align: start; + --pvs-rows: 9.4% 48% 8.4% 26.2% 8%; + --pvs-phone-gutter: 6%; + --pvs-phone-gallery-cols: 1.5fr 0.9fr; + --pvs-drift: 1; + --pvs-entry-cols: var(--pvs-w7) minmax(0, 1fr); + --pvs-entry-flip-cols: minmax(0, 1fr) var(--pvs-w7); +} + +/* Freeform's one move on the landing hero: the print cut loose of the + grid, with the copy holding the page's left measure. */ +.dcx-proof--board[data-dcx-layout="freeform"] > .picker-artboard .ps-desktop .ps-hero { + position: relative; + display: block; + padding: 0; +} + +.dcx-proof--board[data-dcx-layout="freeform"] > .picker-artboard .ps-desktop .ps-hero > .ps-image { + position: absolute; + inset: 0; + height: 100%; + clip-path: polygon(40% 0, 100% 0, 100% 78%, 66% 84%); +} + +.dcx-proof--board[data-dcx-layout="freeform"] > .picker-artboard .ps-desktop .ps-hero > .ps-hero-copy { + position: relative; + z-index: 1; + box-sizing: border-box; + width: 44%; + height: 100%; + align-content: center; + padding-left: var(--pvs-gutter, 6%); +} + +/* Freeform on the index: the prints laid down askew with the caption + stepping onto the corner, the committed rules that are surface-scoped + on screen and read the frame's surface mark here. */ +.dcx-proof--board[data-dcx-layout="freeform"][data-dcx-surface="experience"] > .picker-artboard .ps-index-row > .ps-image { + rotate: -1.7deg; +} + +.dcx-proof--board[data-dcx-layout="freeform"][data-dcx-surface="experience"] > .picker-artboard .ps-index-row--flip > .ps-image { + rotate: 1.4deg; +} + +.dcx-proof--board[data-dcx-layout="freeform"][data-dcx-surface="experience"] > .picker-artboard .ps-index-cap { + position: relative; + z-index: 1; + translate: -9% 0; +} + +.dcx-proof--board[data-dcx-layout="freeform"][data-dcx-surface="experience"] > .picker-artboard .ps-index-row--flip > .ps-index-cap { + translate: 9% 0; +} /* The scale sheet and specimen size themselves against their rail on screen 05; in the document they stand at natural height and full width. */ diff --git a/picker/styles/picker.css b/picker/styles/picker.css index 139b3284c..a06fb0e13 100644 --- a/picker/styles/picker.css +++ b/picker/styles/picker.css @@ -1429,6 +1429,17 @@ body.picker-page { height: calc(5.58708 * var(--pv-x)); background: var(--pv-primary); border-radius: 2px; + display: grid; + place-items: center; + color: var(--pv-neutral); +} + +.pv-pill::after { + content: ""; + width: calc(8.5 * var(--pv-x)); + height: calc(1.3 * var(--pv-x)); + background: currentColor; + border-radius: 2px; } /* The hero is a size container so the page it draws scales with the card rather @@ -1951,7 +1962,7 @@ body.picker-page { flex: none; width: calc(6.92 * var(--pv-x)); height: var(--h); - background: var(--po-wash); + background: var(--po-ink-soft); } .po-chart .po-peak { @@ -2051,10 +2062,10 @@ body.picker-page { /* A square stood on its corner, two borders lit. Half of it falls outside the drawn chevron, so the margins are placing the tip rather than the box. */ .po-chev { - align-self: start; + align-self: center; width: calc(2 * var(--pv-x)); aspect-ratio: 1; - margin: calc(1.86 * var(--pv-x)) calc(3.14 * var(--pv-x)) 0 auto; + margin: 0 calc(3.14 * var(--pv-x)) 0 auto; border-right: 1px solid var(--po-ink); border-bottom: 1px solid var(--po-ink); transform: rotate(45deg); @@ -2154,8 +2165,9 @@ body.picker-page { } .po-phone-body .po-chev { + align-self: center; width: calc(2.77 * var(--pv-x)); - margin: calc(2.65 * var(--pv-x)) calc(5.03 * var(--pv-x)) 0 auto; + margin: 0 calc(5.03 * var(--pv-x)) 0 auto; } .po-prow {