@struq/skill 0.5.2 → 0.5.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (65) hide show
  1. package/README.md +27 -27
  2. package/package.json +2 -2
  3. package/skills/struq/SKILL.md +168 -165
  4. package/skills/struq/blocks/CATALOG.md +49 -46
  5. package/skills/struq/blocks/backgrounds/background-aurora.tsx +2 -1
  6. package/skills/struq/blocks/backgrounds/background-facets.tsx +5 -3
  7. package/skills/struq/blocks/backgrounds/background-silk.tsx +6 -2
  8. package/skills/struq/blocks/catalog.json +50 -5
  9. package/skills/struq/blocks/film.json +11 -7
  10. package/skills/struq/blocks/footers/footer-contact.tsx +8 -78
  11. package/skills/struq/blocks/headers/header-bar.tsx +144 -29
  12. package/skills/struq/blocks/headers/menu-curtain.tsx +36 -19
  13. package/skills/struq/blocks/heroes/hero-poster.tsx +36 -10
  14. package/skills/struq/blocks/kit/HeroCanvas.tsx +6 -2
  15. package/skills/struq/blocks/kit/SplitHeadline.tsx +2 -1
  16. package/skills/struq/blocks/kit/accent.ts +29 -3
  17. package/skills/struq/blocks/kit/blocks.css +530 -6
  18. package/skills/struq/blocks/kit/feel.ts +183 -0
  19. package/skills/struq/blocks/kit/gsap.ts +9 -6
  20. package/skills/struq/blocks/kit/middle/PlaceHours.tsx +254 -0
  21. package/skills/struq/blocks/kit/middle/ProcessStrip.tsx +428 -0
  22. package/skills/struq/blocks/kit/middle/ServicesList.tsx +496 -0
  23. package/skills/struq/blocks/kit/middle/entrance.ts +98 -0
  24. package/skills/struq/blocks/kit/middle/hours.ts +154 -0
  25. package/skills/struq/blocks/kit/middle/index.ts +14 -0
  26. package/skills/struq/blocks/kit/motion/HoverLink.tsx +33 -0
  27. package/skills/struq/blocks/kit/motion/ImageCurtain.tsx +79 -0
  28. package/skills/struq/blocks/kit/motion/MaskWipe.tsx +91 -0
  29. package/skills/struq/blocks/kit/motion/Pressable.tsx +58 -0
  30. package/skills/struq/blocks/kit/motion/RevealText.tsx +103 -0
  31. package/skills/struq/blocks/kit/motion/Rise.tsx +77 -0
  32. package/skills/struq/blocks/kit/motion/ScrubLine.tsx +108 -0
  33. package/skills/struq/blocks/kit/motion/index.ts +11 -0
  34. package/skills/struq/blocks/kit/quiet/Close.tsx +178 -52
  35. package/skills/struq/blocks/kit/quiet/Statement.tsx +3 -2
  36. package/skills/struq/blocks/kit/subject/AppScreen.tsx +388 -0
  37. package/skills/struq/blocks/kit/subject/Document.tsx +742 -0
  38. package/skills/struq/blocks/kit/subject/Mark.tsx +44 -0
  39. package/skills/struq/blocks/kit/subject/PatternPaper.tsx +410 -0
  40. package/skills/struq/blocks/kit/subject/SectionDrawing.tsx +349 -0
  41. package/skills/struq/blocks/kit/subject/Ticket.tsx +354 -0
  42. package/skills/struq/blocks/kit/subject/build.ts +66 -0
  43. package/skills/struq/blocks/kit/subject/draw.ts +196 -0
  44. package/skills/struq/blocks/kit/subject/drawings.ts +373 -0
  45. package/skills/struq/blocks/kit/subject/format.ts +122 -0
  46. package/skills/struq/blocks/kit/subject/index.ts +11 -0
  47. package/skills/struq/blocks/kit/subject/patterns.ts +204 -0
  48. package/skills/struq/blocks/preloaders/preloader-stack.tsx +75 -22
  49. package/skills/struq/blocks/showpieces/hero-opener.tsx +55 -7
  50. package/skills/struq/blocks/showpieces/image-to-fullbleed.tsx +64 -6
  51. package/skills/struq/blocks/showpieces/manifesto-scrub.tsx +56 -3
  52. package/skills/struq/blocks/showpieces/panel-wipe.tsx +93 -11
  53. package/skills/struq/blocks/showpieces/wordmark-finale.tsx +38 -5
  54. package/skills/struq/canon/canon.json +1 -1
  55. package/skills/struq/references/art-direction.md +51 -0
  56. package/skills/struq/scripts/blocks.mjs +56 -20
  57. package/skills/struq/scripts/canon.mjs +36 -7
  58. package/skills/struq/scripts/check.mjs +417 -11
  59. package/skills/struq/scripts/draw.mjs +49 -0
  60. package/skills/struq/scripts/film-check.mjs +28 -4
  61. package/skills/struq/scripts/gate.mjs +13 -3
  62. package/skills/struq/scripts/hand.mjs +222 -0
  63. package/skills/struq/scripts/images.mjs +12 -3
  64. package/skills/struq/scripts/look.mjs +1184 -0
  65. package/skills/struq/scripts/stamp.mjs +47 -0
@@ -0,0 +1,108 @@
1
+ "use client";
2
+ // components/struq/kit/motion/ScrubLine.tsx (Struq recipe)
3
+ // A rule or a drawn path that draws itself as the reader scrolls and undraws going back. Use it for a divider that
4
+ // grows into a section, a timeline's spine, a route on a map, an underline under a statement. Extracted from
5
+ // sections/approach's thread (a line drawn by scroll progress, linear, with the in-flow smoothing).
6
+ //
7
+ // <ScrubLine className="my-16" />
8
+ // <ScrubLine path="M2 40 C 120 0, 240 80, 398 30" viewBox="0 0 400 80" className="h-20 w-full text-accent" />
9
+ //
10
+ // Props
11
+ // - path: an SVG path's d. Without it, a straight rule.
12
+ // - viewBox: the path's viewBox (default "0 0 100 100"). strokeWidth: in the viewBox's units (default 1.5).
13
+ // - axis: the rule's direction, "x" (default, drawn left to right) or "y" (top to bottom; give it a height).
14
+ // - thickness: the rule's weight in px (default 1).
15
+ // - start, end: ScrollTrigger positions for the line's own top (default "top 85%" to "top 35%").
16
+ // - className: on the rule or the svg. It draws in currentColor.
17
+ //
18
+ // Motion: progress follows the scroll, linear, with the feel's scrub.flow smoothing; a path draws along its length
19
+ // (one dash as long as the measured path, so any path draws at an even pace). Reduced motion, no scripts or the server render: fully drawn.
20
+ import { useRef } from "react";
21
+ import { feel, prefersReduced } from "../feel";
22
+ import { gsap, useGSAP } from "../gsap";
23
+
24
+ type Props = {
25
+ path?: string;
26
+ viewBox?: string;
27
+ strokeWidth?: number;
28
+ axis?: "x" | "y";
29
+ thickness?: number;
30
+ start?: string;
31
+ end?: string;
32
+ className?: string;
33
+ };
34
+
35
+ export function ScrubLine({
36
+ path,
37
+ viewBox = "0 0 100 100",
38
+ strokeWidth = 1.5,
39
+ axis = "x",
40
+ thickness = 1,
41
+ start = "top 85%",
42
+ end = "top 35%",
43
+ className = "",
44
+ }: Props) {
45
+ const ref = useRef<HTMLSpanElement & SVGSVGElement>(null);
46
+
47
+ useGSAP(
48
+ () => {
49
+ const el = ref.current;
50
+ if (!el) return;
51
+ if (prefersReduced()) {
52
+ el.dataset.ready = "1";
53
+ return;
54
+ }
55
+ const f = feel(el);
56
+ const scrollTrigger = { trigger: el, start, end, scrub: f.scrub.flow };
57
+ const line = path ? el.querySelector("path") : el;
58
+ if (!line) return;
59
+ if (path) {
60
+ // The path's own measured length: one dash as long as the path, offset by all of it, then by none.
61
+ const length = (line as SVGPathElement).getTotalLength();
62
+ gsap.set(line, { attr: { "stroke-dasharray": `${length} ${length}` } });
63
+ gsap.fromTo(
64
+ line,
65
+ { attr: { "stroke-dashoffset": length } },
66
+ { attr: { "stroke-dashoffset": 0 }, ease: f.ease.scrub, scrollTrigger },
67
+ );
68
+ } else {
69
+ gsap.fromTo(
70
+ line,
71
+ axis === "x" ? { scaleX: 0 } : { scaleY: 0 },
72
+ { ...(axis === "x" ? { scaleX: 1 } : { scaleY: 1 }), ease: f.ease.scrub, scrollTrigger },
73
+ );
74
+ }
75
+ el.dataset.ready = "1";
76
+ },
77
+ { scope: ref, dependencies: [path, axis, start, end] },
78
+ );
79
+
80
+ if (path) {
81
+ return (
82
+ <svg
83
+ ref={ref}
84
+ data-scrub-line="path"
85
+ viewBox={viewBox}
86
+ fill="none"
87
+ aria-hidden
88
+ className={`block ${className}`}
89
+ >
90
+ <path
91
+ d={path}
92
+ stroke="currentColor"
93
+ strokeWidth={strokeWidth}
94
+ strokeLinecap="butt"
95
+ />
96
+ </svg>
97
+ );
98
+ }
99
+ return (
100
+ <span
101
+ ref={ref}
102
+ aria-hidden
103
+ data-scrub-line={axis}
104
+ className={`block bg-current ${className}`}
105
+ style={axis === "x" ? { height: thickness } : { width: thickness }}
106
+ />
107
+ );
108
+ }
@@ -0,0 +1,11 @@
1
+ // components/struq/kit/motion/index.ts (Struq recipe)
2
+ // The motion primitives: the house moves with the craft built in (reduced motion, cleanup, descender-safe masks, no
3
+ // layout shift), timed by the site's temperament (../feel, data-temperament on <body>). Use these instead of writing
4
+ // GSAP for a reveal, a block rising, a wipe, a curtain, a link hover, a button press or a scroll-drawn line.
5
+ export { HoverLink } from "./HoverLink";
6
+ export { ImageCurtain } from "./ImageCurtain";
7
+ export { MaskWipe } from "./MaskWipe";
8
+ export { Pressable } from "./Pressable";
9
+ export { RevealText } from "./RevealText";
10
+ export { Rise, riseFrom, riseTo } from "./Rise";
11
+ export { ScrubLine } from "./ScrubLine";
@@ -1,72 +1,198 @@
1
1
  "use client";
2
2
  // components/struq/kit/quiet/Close.tsx (Struq recipe)
3
- // The page's last call: one line of type at the sheet's moment size from the grid's first column, and one link at the
4
- // far end of the line under it, so the eye crosses the page once, from the big line to the small way out. An optional
5
- // hairline frame around the line is the frame motif's last echo; an optional caption sits at the start of the link's
6
- // line, a label in the margin columns beside the line.
3
+ // The page's last scene before the footer, built from the motion primitives (../motion) and timed by the site's
4
+ // temperament. Three shapes; none of them is the site's name at full width, which is never a close.
7
5
  //
8
- // <Close line="Kom kijken in de werkplaats." accent="werkplaats" link={{ href: "/contact", label: "Maak een afspraak" }}
9
- // caption="Open op zaterdag, 10 tot 16 uur" frame />
6
+ // - "idea": the idea's last line rises out of its masks (RevealText), a ScrubLine draws the motif's line under it as
7
+ // the reader arrives, and the doors sit below. For a site whose last word is the idea itself.
8
+ // - "echo": the opening comes back smaller. Its first line wipes in (MaskWipe) or its photo is uncovered
9
+ // (ImageCurtain), at a fraction of its first size, with the doors beside or under it. For a film that ends where it
10
+ // began.
11
+ // - "door": the brief gave real ways in (an address, a phone number, an email, a booking or shop URL) and they are the
12
+ // close: set large, each a HoverLink (or a Pressable for a booking or a shop), with the idea in one line above. For
13
+ // a place people visit, call or book.
14
+ //
15
+ // <Close shape="idea" line="Grown slowly, poured by hand." accent="slowly" motif={{ path: "M2 40 C 120 0, 240 80, 398 30", viewBox: "0 0 400 80" }}
16
+ // doors={[{ kind: "email", href: "mailto:hello@kiln.studio", label: "hello@kiln.studio" }]} />
17
+ // <Close shape="echo" echo={{ media: <img src="/hero.jpg" alt="The kiln at dawn" className="h-full w-full object-cover" /> }} line="Back to the kiln." />
18
+ // <Close shape="door" line="Bread from four in the morning." doors={[
19
+ // { kind: "address", href: "https://maps.app.goo.gl/...", label: "Oudegracht 12, Utrecht" },
20
+ // { kind: "phone", href: "tel:+31301234567", label: "030 123 45 67" },
21
+ // { kind: "booking", href: "https://book.example/table", label: "Book a table" },
22
+ // ]} credit="Bakkerij Oud, since 1962" />
10
23
  //
11
24
  // Props
12
- // - line: the closing sentence, plain text, short (it sets in two or three lines at moment size).
13
- // - accent: the site's one accent word, again: where it first stands in the line it is set in the pairing's italic
14
- // accent face (--face-accent), as in the opening and the Statement (../accent). A word the line does not hold
15
- // changes nothing.
16
- // - link: { href, label }, the one way out. Rendered as a plain <a>; wrap your own Link around it if you route.
17
- // - frame: draws a hairline from --line around the line, one gutter inside it. Use it only when the site's motif is the
18
- // frame (it echoes the hero's or the centerpiece's frame).
19
- // - caption: small, at the start of the link's line. label: small, beside the line in the margin columns.
25
+ // - shape: "idea" (default), "echo" or "door".
26
+ // - line: the idea's line, plain text. idea: the line itself (short, two or three lines at h2). door: one line above
27
+ // the doors. echo: optional, a short lead beside the echo.
28
+ // - accent: the site's one accent word, again: set in the pairing's italic accent face where it first stands in line
29
+ // or echo.line (../accent). A word the line does not hold changes nothing.
30
+ // - echo (shape "echo"): { line?: string; media?: ReactNode; reveal?: "wipe" | "curtain"; className?: string }. line is
31
+ // the opening's first line, set at h2 (not the opening's poster size); media is the opening's photo (an img, a
32
+ // next/image with fill), shown at about half the page's width, sized by className (default aspect-[4/3]). reveal:
33
+ // "curtain" (default for media) or "wipe" (always for a line).
34
+ // - motif (shape "idea"): { path?: string; viewBox?: string }, the ScrubLine under the line. A path echoes a drawn
35
+ // motif; without one it is a straight rule.
36
+ // - doors: the real ways in, from the brief only: { label, href?, kind? } with kind "address" | "phone" | "email" |
37
+ // "booking" | "shop" | "link". With an href a door is a HoverLink, or a Pressable when it is a booking or a shop;
38
+ // an address without an href is plain text. With no doors given nothing is rendered for them: never a placeholder,
39
+ // never an invitation without a destination.
40
+ // - credit: a small line at the foot (credit, legal, year). wordmark: the name at text size in the foot, if at all.
41
+ // - look: the HoverLink look, the site's one ("draw" default, "slide", "color").
20
42
  // - className: on the root, for example "scene-inverse" or "scene-field".
21
43
  //
22
- // Mounting: the last section before the footer. The root carries data-scene="close" and data-energy="1".
23
- // Motion: it enters once. The line's rows rise through their masks (SplitHeadline), the caption and the link follow
24
- // (Reveal). No pin, no scrub, no hover motion: the link is underlined at rest and stays so. Reduced motion: a short
25
- // fade. Without scripts: the composed scene. Phones: the line, the label, then the link with the caption under it.
44
+ // Mounting: the last section before the footer. The root carries data-scene="close", data-energy="1" and
45
+ // data-close-shape. Motion: it enters once, from the primitives: RevealText on the line, ScrubLine scrubbed under it,
46
+ // MaskWipe or ImageCurtain on the echo; doors answer hover and press by the feel. No pin. Reduced motion, no scripts
47
+ // or the server render: every primitive shows its final state. Phones: one column, the doors stacked.
48
+ import type { ReactNode } from "react";
26
49
  import { withAccent } from "../accent";
27
- import { Reveal } from "../Reveal";
28
- import { SplitHeadline } from "../SplitHeadline";
50
+ import { HoverLink } from "../motion/HoverLink";
51
+ import { ImageCurtain } from "../motion/ImageCurtain";
52
+ import { MaskWipe } from "../motion/MaskWipe";
53
+ import { Pressable } from "../motion/Pressable";
54
+ import { RevealText } from "../motion/RevealText";
55
+ import { ScrubLine } from "../motion/ScrubLine";
29
56
  import { LABEL, SCENE_SPACE, SHEET_GRID } from "./sheet";
30
57
 
58
+ export type CloseShape = "idea" | "echo" | "door";
59
+
60
+ export type Door = {
61
+ label: string;
62
+ href?: string;
63
+ kind?: "address" | "phone" | "email" | "booking" | "shop" | "link";
64
+ };
65
+
31
66
  type Props = {
32
- line: string;
67
+ shape?: CloseShape;
68
+ line?: string;
33
69
  accent?: string;
34
- link: { href: string; label: string };
35
- frame?: boolean;
36
- caption?: string;
37
- label?: string;
70
+ echo?: { line?: string; media?: ReactNode; reveal?: "wipe" | "curtain"; className?: string };
71
+ motif?: { path?: string; viewBox?: string };
72
+ doors?: readonly Door[];
73
+ credit?: string;
74
+ wordmark?: string;
75
+ look?: "draw" | "slide" | "color";
38
76
  className?: string;
39
77
  };
40
78
 
41
- export function Close({ line, accent, link, frame = false, caption, label, className = "" }: Props) {
79
+ /** One door: a Pressable for a booking or a shop, a HoverLink for any other link, plain text without an href. */
80
+ function DoorItem({ door, size, look }: { door: Door; size: "large" | "small"; look: Props["look"] }) {
81
+ const type = size === "large" ? "font-display text-h2" : "font-body text-h3 font-medium";
82
+ if (!door.href) return <p className={`m-0 text-ink ${type}`}>{door.label}</p>;
83
+ if (door.kind === "booking" || door.kind === "shop") {
84
+ return (
85
+ <Pressable
86
+ href={door.href}
87
+ press="fill"
88
+ className={`w-fit px-8 py-4 text-ink shadow-[inset_0_0_0_1px_var(--line)] ${size === "large" ? "font-body text-h3 font-medium" : "font-body text-lead font-medium"}`}
89
+ >
90
+ {door.label}
91
+ </Pressable>
92
+ );
93
+ }
42
94
  return (
43
- <section data-scene="close" data-energy="1" className={`text-ink ${SCENE_SPACE} ${className}`}>
44
- <div className={`items-start gap-y-10 md:items-baseline md:gap-y-20 ${SHEET_GRID}`}>
45
- {/* The frame's inset is in the line's own em, so it holds the mask's room for accents and descenders at any
46
- size and the hairline never crosses a letter. */}
47
- <div className={`col-span-12 md:col-span-10 ${frame ? "border border-line p-[0.35em] text-sheet-moment" : ""}`}>
48
- <SplitHeadline as="h2" on="scroll" className="m-0 text-sheet-moment">
49
- {withAccent(line, accent)}
50
- </SplitHeadline>
51
- </div>
52
- {label ? (
53
- <Reveal y={16} className="col-span-8 md:col-span-2 md:col-start-11">
54
- <p className={LABEL}>{label}</p>
55
- </Reveal>
95
+ <HoverLink href={door.href} look={look} className={`w-fit text-ink ${type}`}>
96
+ {door.label}
97
+ </HoverLink>
98
+ );
99
+ }
100
+
101
+ function Doors({ doors, size, look, className = "" }: { doors?: readonly Door[]; size: "large" | "small"; look: Props["look"]; className?: string }) {
102
+ if (!doors || doors.length === 0) return null;
103
+ return (
104
+ <ul className={`m-0 flex list-none flex-col items-start p-0 ${size === "large" ? "gap-6 md:gap-8" : "gap-4"} ${className}`}>
105
+ {doors.map((door) => (
106
+ <li key={`${door.kind ?? "link"}:${door.label}`}>
107
+ <DoorItem door={door} size={size} look={look} />
108
+ </li>
109
+ ))}
110
+ </ul>
111
+ );
112
+ }
113
+
114
+ function Foot({ credit, wordmark }: { credit?: string; wordmark?: string }) {
115
+ if (!credit && !wordmark) return null;
116
+ return (
117
+ <div className="col-span-12 flex flex-col gap-1 border-t border-line pt-5 md:flex-row md:items-baseline md:justify-between">
118
+ {wordmark ? <p className="m-0 font-body text-body font-medium text-ink">{wordmark}</p> : null}
119
+ {credit ? <p className={LABEL}>{credit}</p> : null}
120
+ </div>
121
+ );
122
+ }
123
+
124
+ export function Close({
125
+ shape = "idea",
126
+ line,
127
+ accent,
128
+ echo,
129
+ motif,
130
+ doors,
131
+ credit,
132
+ wordmark,
133
+ look = "draw",
134
+ className = "",
135
+ }: Props) {
136
+ return (
137
+ <section data-scene="close" data-energy="1" data-close-shape={shape} className={`text-ink ${SCENE_SPACE} ${className}`}>
138
+ <div className={`items-start gap-y-12 md:gap-y-20 ${SHEET_GRID}`}>
139
+ {shape === "idea" ? (
140
+ <>
141
+ {line ? (
142
+ <RevealText as="h2" by="lines" className="col-span-12 m-0 max-w-[20ch] font-display text-h2 md:col-span-9">
143
+ {withAccent(line, accent)}
144
+ </RevealText>
145
+ ) : null}
146
+ <div className="col-span-12 text-accent">
147
+ {motif?.path ? (
148
+ <ScrubLine path={motif.path} viewBox={motif.viewBox ?? "0 0 400 80"} className="h-16 w-full md:h-24" />
149
+ ) : (
150
+ <ScrubLine />
151
+ )}
152
+ </div>
153
+ <Doors doors={doors} size="small" look={look} className="col-span-12 md:col-span-6 md:col-start-7" />
154
+ </>
56
155
  ) : null}
57
- {/* The link first in reading order; on wide screens it takes the far end and the caption the start. */}
58
- <Reveal
59
- y={16}
60
- className="col-span-12 flex flex-col items-start gap-4 md:flex-row-reverse md:items-baseline md:justify-between md:gap-10"
61
- >
62
- <a
63
- href={link.href}
64
- className="font-body text-h3 font-medium text-ink underline decoration-1 underline-offset-[0.22em]"
65
- >
66
- {link.label}
67
- </a>
68
- {caption ? <p className={`${LABEL} max-w-[40ch]`}>{caption}</p> : null}
69
- </Reveal>
156
+
157
+ {shape === "echo" ? (
158
+ <>
159
+ {echo?.media ? (
160
+ (echo.reveal ?? "curtain") === "curtain" ? (
161
+ <ImageCurtain className={`col-span-12 md:col-span-6 ${echo.className ?? "aspect-[4/3]"}`}>{echo.media}</ImageCurtain>
162
+ ) : (
163
+ <MaskWipe from="left" settle className={`relative col-span-12 overflow-hidden md:col-span-6 ${echo.className ?? "aspect-[4/3]"}`}>
164
+ {echo.media}
165
+ </MaskWipe>
166
+ )
167
+ ) : null}
168
+ {echo?.line ? (
169
+ <MaskWipe from="left" className={`col-span-12 ${echo.media ? "md:col-span-6" : "md:col-span-9"}`}>
170
+ <p className="m-0 max-w-[20ch] font-display text-h2">{withAccent(echo.line, accent)}</p>
171
+ </MaskWipe>
172
+ ) : null}
173
+ <div className={`col-span-12 flex flex-col gap-8 ${echo?.media && !echo.line ? "md:col-span-5 md:col-start-8 md:self-end" : "md:col-span-6 md:col-start-7"}`}>
174
+ {line ? (
175
+ <RevealText as="p" by="lines" className="m-0 max-w-[32ch] font-body text-lead text-ink-muted">
176
+ {withAccent(line, accent)}
177
+ </RevealText>
178
+ ) : null}
179
+ <Doors doors={doors} size="small" look={look} />
180
+ </div>
181
+ </>
182
+ ) : null}
183
+
184
+ {shape === "door" ? (
185
+ <>
186
+ {line ? (
187
+ <RevealText as="p" by="lines" className="col-span-12 m-0 max-w-[40ch] font-body text-lead text-ink-muted md:col-span-8">
188
+ {withAccent(line, accent)}
189
+ </RevealText>
190
+ ) : null}
191
+ <Doors doors={doors} size="large" look={look} className="col-span-12" />
192
+ </>
193
+ ) : null}
194
+
195
+ <Foot credit={credit} wordmark={wordmark} />
70
196
  </div>
71
197
  </section>
72
198
  );
@@ -12,8 +12,9 @@
12
12
  // Props
13
13
  // - children: the sentence, plain text. Two to five lines at moment size on a wide screen.
14
14
  // - accent: one word of the sentence, set in the pairing's italic accent face (--face-accent) where it first stands
15
- // (whole word, any case; punctuation stays outside). The site's one accent word: the opening and the Close carry it
16
- // too (../accent). A word the sentence does not hold changes nothing.
15
+ // (whole word, any case; punctuation stays outside the mark but on its line, so a phone never sets the full stop
16
+ // alone). The site's one accent word: the opening and the Close carry it too (../accent). A word the sentence does
17
+ // not hold changes nothing.
17
18
  // - label: small, sentence case, body face. Beside the first line (wide screens), under the sentence (phones).
18
19
  // - image: a StruqImage, shown upright (4/5) and small: two columns wide, five on a phone.
19
20
  // - as: "h2" (default) or "p" when the page already has its heading here.