mirror of
https://github.com/pbakaus/impeccable.git
synced 2026-09-12 22:26:38 +03:00
339 lines
16 KiB
CSS
339 lines
16 KiB
CSS
/* ============================================================
|
|
Screen 07: layout structure.
|
|
|
|
Every other structural screen changes something you can see on its own: a
|
|
divider is there or it is not, a corner is round or it is square. This one
|
|
changes proportion, and a proportion is invisible without a ruler. Four
|
|
pages with the columns nudged a few points apart are four identical pages.
|
|
|
|
So the ruler is drawn. The measure below is a real twelve-column grid, and
|
|
the three disciplined answers place every block on an exact column count:
|
|
what changes between them is which spans the page spends its columns on.
|
|
Freeform is then the one answer that crosses the lines, and it reads as a
|
|
decision because the thing it is breaking is on screen next to it.
|
|
|
|
Two selectors per option, the shape screen 03 established. The first is the
|
|
hover preview and belongs to this screen alone. The second is the committed
|
|
answer and reaches every artboard marked data-carry, which is this screen
|
|
plus boundaries, corners, and depth, so each later question is asked about
|
|
the page as it has been chosen so far. The measure itself does not travel:
|
|
it is an instrument for this question, drawn only where it is asked.
|
|
============================================================ */
|
|
|
|
/* ── The measure ─────────────────────────────────────────────
|
|
Twelve columns and eleven gutters inside the page margins, so a column is
|
|
(100% - 11 x 1.6%) / 12. The span variables are the width of n columns
|
|
including the gutters they swallow, which is what a grid track needs and
|
|
what makes an answer legible: --pvs-w7 against --pvs-w5 is a seven-five
|
|
hero, and it is written that way rather than as 57.6667%.
|
|
|
|
Percentages resolve against the box they are used in. Every section's
|
|
content box is the page width, so spans hold there; the gallery sits inside
|
|
one editorial track, so its gutter is scaled by that track's share. The
|
|
ladder runs to ten because the widest gallery track is a ten-column one,
|
|
and each answer's gallery gutter is derived from the number here.
|
|
|
|
These are the numbers for a page that takes the whole field. Editorial
|
|
takes eleven of the field's twelve columns and re-fits the same ladder to
|
|
its own width, in its own block below. */
|
|
[data-carry] {
|
|
--pvs-gut: 1.6%;
|
|
--pvs-w1: 6.8667%;
|
|
--pvs-w2: 15.3333%;
|
|
--pvs-w3: 23.8%;
|
|
--pvs-w4: 32.2667%;
|
|
--pvs-w5: 40.7333%;
|
|
--pvs-w6: 49.2%;
|
|
--pvs-w7: 57.6667%;
|
|
--pvs-w8: 66.1333%;
|
|
--pvs-w9: 74.6%;
|
|
--pvs-w10: 83.0667%;
|
|
}
|
|
|
|
/* The page's own margins are asymmetric under two of the answers, and a
|
|
drawn grid makes it obvious when only some rows honor them. Chrome and the
|
|
editorial band are brought onto the same measure as the hero and the proof
|
|
band. Scoped to the structural artboards: screens 03 and 04 are judging
|
|
color and glyphs, and their page is not under a ruler. */
|
|
[data-carry] :is(.ps-nav, .ps-editorial, .ps-footer) {
|
|
padding-right: var(--pvs-gutter-end);
|
|
}
|
|
|
|
/* The proof band divides in four, which on a twelve-column page means each
|
|
claim takes three columns and each divider sits in a gutter. It was four
|
|
equal shares of whatever was left after a fixed 25px gap, which lands a few
|
|
pixels off every column line: close enough to pass unnoticed on a bare
|
|
page, and the one row that looks wrong once the lines are drawn. */
|
|
[data-carry] .ps-desktop > .ps-proof {
|
|
grid-template-columns:
|
|
var(--pvs-w3) auto
|
|
var(--pvs-w3) auto
|
|
var(--pvs-w3) auto
|
|
minmax(0, 1fr);
|
|
column-gap: calc(var(--pvs-gut) / 2);
|
|
}
|
|
|
|
/* Eleven hairlines, one down the middle of each gutter, rather than the
|
|
filled columns a grid tool draws. Filled columns cover four fifths of the
|
|
page and turn it into wallpaper at any tint dark enough to see, and the
|
|
gutter is ten pixels wide at this size, so painting it whole gives a stripe
|
|
rather than a line. The centre line carries the same information and
|
|
carries it better: where two blocks are on the grid, the mark lands dead
|
|
centre in the gap between them, and where one is not, it does not.
|
|
|
|
Mixed from the artboard's own ink so the field survives a drenched ground,
|
|
and kept under the page so nothing is read through it. */
|
|
|
|
/* The field is nailed to six and six and carries its own twelve columns
|
|
rather than reading the answer's margins and the ladder above. A measure
|
|
that re-fits itself to whatever page is on it is not a measure: the origin
|
|
and the column width would both follow the answer, and four pages each
|
|
checked against a ruler cut to fit would be four pages checked against
|
|
nothing. The instrument is the same one under all four. What moves is the
|
|
page standing on it, which is the whole of what this screen is asking. */
|
|
.picker-preview-layout .ps-desktop {
|
|
position: relative;
|
|
isolation: isolate;
|
|
}
|
|
|
|
.picker-preview-layout .ps-desktop::before {
|
|
--pvs-field-col: 6.8667%;
|
|
--pvs-field-gut: 1.6%;
|
|
--pvs-mark: calc(var(--pvs-field-col) + var(--pvs-field-gut) / 2);
|
|
|
|
content: "";
|
|
position: absolute;
|
|
z-index: -1;
|
|
inset: 0 6%;
|
|
background-image: repeating-linear-gradient(
|
|
to right,
|
|
transparent 0 calc(var(--pvs-mark) - 0.5px),
|
|
color-mix(in oklab, var(--pvs-ink) 17%, transparent)
|
|
calc(var(--pvs-mark) - 0.5px) calc(var(--pvs-mark) + 0.5px),
|
|
transparent calc(var(--pvs-mark) + 0.5px)
|
|
calc(var(--pvs-field-col) + var(--pvs-field-gut))
|
|
);
|
|
pointer-events: none;
|
|
}
|
|
|
|
/* The handset has one column, so twelve bands would say nothing there. What
|
|
the answer changes on a phone is the measure itself and whether anything
|
|
is allowed to cross it, so the two content edges are the whole ruler. */
|
|
.picker-preview-layout .ps-phone-body {
|
|
position: relative;
|
|
isolation: isolate;
|
|
}
|
|
|
|
.picker-preview-layout .ps-phone-body::before {
|
|
content: "";
|
|
position: absolute;
|
|
z-index: -1;
|
|
top: 0;
|
|
bottom: 0;
|
|
left: var(--pvs-phone-gutter, 6%);
|
|
right: var(--pvs-phone-gutter, 6%);
|
|
border-inline: 1px solid color-mix(in oklab, var(--pvs-ink) 12%, transparent);
|
|
pointer-events: none;
|
|
}
|
|
|
|
/* ── Simple grid ─────────────────────────────────────────────
|
|
Six and six, four cards of two, equal margins, bands of near-equal weight.
|
|
Everything starts and stops on a line, and the thing to notice is that
|
|
there is nothing to notice. */
|
|
#picker-form:has(.picker-strategy-option:hover input[name="layout-structure"][value="simple-grid"]) .picker-preview-layout,
|
|
:where(#picker-form:not(:has(.picker-strategy-option:hover input[name="layout-structure"])):has(input[name="layout-structure"][value="simple-grid"]:checked)) [data-carry] {
|
|
--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);
|
|
/* Four equal cards of two columns need no ratio. The gap is the page
|
|
gutter restated as a share of the eight-column track it sits inside. */
|
|
--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;
|
|
}
|
|
|
|
/* ── Balanced ────────────────────────────────────────────────
|
|
The same grid, spent unevenly. The hero leans five-seven and the lead card
|
|
takes three columns where its neighbours take two. Both breaks land on the
|
|
lines: the emphasis is chosen, the discipline is not loosened. */
|
|
#picker-form:has(.picker-strategy-option:hover input[name="layout-structure"][value="balanced"]) .picker-preview-layout,
|
|
:where(#picker-form:not(:has(.picker-strategy-option:hover input[name="layout-structure"])):has(input[name="layout-structure"][value="balanced"]:checked)) [data-carry] {
|
|
--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);
|
|
/* Three columns then three of two. The tracks are fr in the same
|
|
proportion as the spans, because fr cannot take a percentage variable,
|
|
and the gap is the page gutter inside a nine-column track. */
|
|
--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;
|
|
}
|
|
|
|
/* ── Editorial ───────────────────────────────────────────────
|
|
Uneven margins, a standing text column at seven against a portrait at four,
|
|
a single column of section copy beside a nine-column gallery, and a hero
|
|
band that takes most of the page. Still every edge on a line: this is the
|
|
grid used with nerve, not abandoned. Copy hangs from the top of each band
|
|
the way a column of text hangs from a rule.
|
|
|
|
The wide left margin is a whole column of the field rather than a round
|
|
number of its own: the page starts where the second column starts and ends
|
|
where the field ends, so it keeps eleven of the twelve. An answer is
|
|
allowed to spend fewer columns than the page has. It is not allowed to
|
|
spend them at a size the measure does not recognise, which is what a
|
|
margin picked for its look does. */
|
|
#picker-form:has(.picker-strategy-option:hover input[name="layout-structure"][value="editorial"]) .picker-preview-layout,
|
|
:where(#picker-form:not(:has(.picker-strategy-option:hover input[name="layout-structure"])):has(input[name="layout-structure"][value="editorial"]:checked)) [data-carry] {
|
|
--pvs-gutter: 13.4507%;
|
|
--pvs-gutter-end: 6%;
|
|
/* The ladder above, re-fitted. A column and a gutter are the same number of
|
|
pixels here as under the other three answers and a larger share of a page
|
|
one column narrower, so every span still stops on a drawn line. The
|
|
answer is written the way it was: --pvs-w7 against the rest is still a
|
|
seven, now a seven of eleven. */
|
|
--pvs-gut: 1.748%;
|
|
--pvs-w1: 7.5018%;
|
|
--pvs-w2: 16.7516%;
|
|
--pvs-w3: 26.0015%;
|
|
--pvs-w4: 35.2513%;
|
|
--pvs-w5: 44.5011%;
|
|
--pvs-w6: 53.7509%;
|
|
--pvs-w7: 63.0007%;
|
|
--pvs-w8: 72.2505%;
|
|
--pvs-w9: 81.5004%;
|
|
--pvs-w10: 90.7502%;
|
|
--pvs-hero-cols: var(--pvs-w7) minmax(0, 1fr);
|
|
--pvs-hero-gap: var(--pvs-gut);
|
|
--pvs-editorial-cols: var(--pvs-w2) minmax(0, 1fr);
|
|
--pvs-editorial-gap: var(--pvs-gut);
|
|
/* A lead card at three columns against three of two, in a nine-column
|
|
track. */
|
|
--pvs-gallery-cols: 26.0015fr 16.7516fr 16.7516fr 16.7516fr;
|
|
--pvs-gallery-gap: calc(var(--pvs-gut) * 100 / 81.5004);
|
|
--pvs-section-align: start;
|
|
--pvs-rows: 8% 57.5% 8.5% 18.5% 7.5%;
|
|
--pvs-phone-gutter: 11%;
|
|
--pvs-phone-gallery-cols: 1.9fr 0.7fr;
|
|
--pvs-phone-bleed: -11%;
|
|
--pvs-phone-bleed-w: 122%;
|
|
}
|
|
|
|
/* ── Freeform ────────────────────────────────────────────────
|
|
Columns of no particular relation, and blocks that leave the field. The
|
|
margins are the first thing off it: the page hangs past the measure on the
|
|
left and stops short of it on the right, before a single block has moved.
|
|
The escapes are listed under the drift flag below. */
|
|
#picker-form:has(.picker-strategy-option:hover input[name="layout-structure"][value="freeform"]) .picker-preview-layout,
|
|
:where(#picker-form:not(:has(.picker-strategy-option:hover input[name="layout-structure"])):has(input[name="layout-structure"][value="freeform"]:checked)) [data-carry] {
|
|
--pvs-gutter: 3.5%;
|
|
--pvs-gutter-end: 9%;
|
|
--pvs-hero-cols: 44% minmax(0, 1fr);
|
|
--pvs-hero-gap: 3%;
|
|
--pvs-editorial-cols: 37% minmax(0, 1fr);
|
|
--pvs-editorial-gap: 2.5%;
|
|
--pvs-gallery-cols: 1.45fr 0.72fr 1.1fr 0.83fr;
|
|
--pvs-gallery-gap: 2.5%;
|
|
--pvs-section-align: end;
|
|
--pvs-rows: 9.4% 48% 8.4% 26.2% 8%;
|
|
--pvs-phone-gutter: 4%;
|
|
--pvs-phone-gallery-cols: 1.5fr 0.9fr;
|
|
--pvs-phone-bleed: 0 -9%;
|
|
--pvs-phone-bleed-w: 109%;
|
|
--pvs-drift: 1;
|
|
}
|
|
|
|
/* ── Leaving the grid ────────────────────────────────────────
|
|
Drift is declared on every artboard and multiplied by a flag only freeform
|
|
raises, so the other three pay nothing for the rules existing.
|
|
|
|
Each escape is a transform or a negative margin, never a change of flow: a
|
|
block that steps out does not push the rest of the page around to make room
|
|
for it, which is the difference between a composition and a broken grid.
|
|
|
|
The moves are chosen so that nothing lands on top of running text. A bar
|
|
half-covered by a picture is what a mistake looks like; a picture running
|
|
off the edge of the page is what a decision looks like. */
|
|
|
|
/* The picture takes the right margin and keeps going, clipped by the frame
|
|
the way a full-bleed image is clipped by the browser window. The width has
|
|
to grow with the offset: the picture carries an explicit width, so a
|
|
negative margin alone would slide it rather than stretch it. */
|
|
[data-carry] .ps-hero > .ps-image {
|
|
width: calc(100% + var(--pvs-drift, 0) * 16%);
|
|
translate: calc(var(--pvs-drift, 0) * 6%) 0;
|
|
}
|
|
|
|
/* The copy sinks below the picture's top edge, so the two blocks in the hero
|
|
no longer share a line. z-index is raised with the same flag: the actions
|
|
below cross onto the picture and have to sit over it. */
|
|
[data-carry] .ps-hero-copy {
|
|
position: relative;
|
|
z-index: var(--pvs-drift, 0);
|
|
translate: 0 calc(var(--pvs-drift, 0) * 12%);
|
|
}
|
|
|
|
/* The one overlap, and the only block allowed one. Two filled controls onto a
|
|
flat picture is a composition that holds anywhere, and it is the one pair
|
|
in the wireframe where the block on top is opaque and the block underneath
|
|
has nothing to read: the same move over a line of copy is what a mistake
|
|
looks like. */
|
|
[data-carry] .ps-hero-copy .ps-actions {
|
|
translate: calc(var(--pvs-drift, 0) * 62%) 0;
|
|
}
|
|
|
|
/* Drift is a desktop move. The handset has one column and a stack sized in
|
|
pixels, so a block stepping out of line there has nowhere to go but through
|
|
the bottom of the frame. */
|
|
[data-carry] .ps-desktop .ps-gallery-item:nth-child(2n) {
|
|
translate: 0 calc(var(--pvs-drift, 0) * 14%);
|
|
}
|
|
|
|
/* The last card leaves the same way the picture did, so the escape reads as
|
|
one decision about the right edge rather than two unrelated nudges. Both
|
|
axes are named because this card is also an even one, and translate is a
|
|
single property. */
|
|
[data-carry] .ps-desktop .ps-gallery-item:last-child {
|
|
margin-right: calc(var(--pvs-drift, 0) * -18%);
|
|
translate: calc(var(--pvs-drift, 0) * 22%) calc(var(--pvs-drift, 0) * 14%);
|
|
}
|
|
|
|
[data-carry] .ps-desktop .ps-editorial-copy {
|
|
translate: 0 calc(var(--pvs-drift, 0) * -12%);
|
|
}
|
|
|
|
/* ── The handset ─────────────────────────────────────────────
|
|
One column still answers the question: in the margin, in how unevenly the
|
|
two cards divide the row, and in whether anything is allowed to cross the
|
|
measure. The picture is the block given that permission, both edges under
|
|
Editorial and the outer edge alone under Freeform. The rhythm between
|
|
blocks is left alone, because the handset's stack is sized in pixels and a
|
|
couple of points of extra gap pushes the card row through the bottom of the
|
|
frame at the narrowest window the picker supports. */
|
|
[data-carry] .ps-phone-body {
|
|
padding-inline: var(--pvs-phone-gutter, 6%);
|
|
}
|
|
|
|
/* The picture carries an explicit width, so a negative margin moves it rather
|
|
than widening it. Both are named together or the bleed slides the block
|
|
sideways instead of stretching it past the measure. */
|
|
[data-carry] .ps-phone-body > .ps-image {
|
|
margin-inline: var(--pvs-phone-bleed, 0);
|
|
width: var(--pvs-phone-bleed-w, 100%);
|
|
}
|
|
|
|
[data-carry] .ps-phone-body .ps-gallery {
|
|
grid-template-columns: var(--pvs-phone-gallery-cols, 1.05fr 0.95fr);
|
|
}
|