← typeset iawriter.css Download

iawriter.css

The iA Writer layer. iA Writer is Markdown only, so a template gets headings, body text, bold, italic, tables, footnotes and one quoting construct and nothing else — and this file is what maps that vocabulary onto typeset.css. It adds no typography of its own; the page, and anything the letter wants for itself, live in letter/page.css.

One template: the letter. Ragged right at the 11pt base, filling an A4 page with 20mm margins, with a display quote and a letterhead of its own — the level-1 heading is the name, and an indented block, stripped of every mark of code, is the address.

It ships as a bundle carrying typeset.css and every font face it binds, because a template is a local page with no network and WebKit substitutes a missing face without saying so. Built from this repository on every deploy, so it cannot drift from the stylesheet above.

There is no two-column iA Writer template. WebKit honours every CSS multi-column property on screen and ignores all of them when printing, so such a template previews in two columns and exports in one, with nothing to say it changed. Two columns belong to an engine that can paginate them: Typst does it natively.

No running head and no folio. iA Writer reserves those bands by setting the page margins itself, so a band and a @page margin cannot both be declared — and the page is the thing worth having.

All the templates → Download the letter template Versioned releases →

272 lines · 10.3 KB

1/* ==========================================================================
2 iawriter.css — the layer between iA Writer's Markdown output and typeset.css.
3
4 Loaded after typeset.css, which does the typography. This file does only the
5 three things typeset.css cannot know about:
6
7 1. binds the bundled font files to the family names the spec asserts;
8 2. maps the handful of constructs MultiMarkdown emits that have no
9 counterpart in a hand-written typeset document — footnotes, citations,
10 task lists, column alignment.
11
12 Everything the letter wants for itself is in letter/page.css: the page, the
13 display quote and the letterhead.
14
15 It adds no typography of its own. Where a rule here sets a size, a colour or
16 a space, it does so through a typeset token so it cannot drift from the spec.
17 ========================================================================== */
18
19/* --- 1. Fonts -------------------------------------------------------------
20 typeset.css names three families and leaves loading them to the document.
21 A template is a local web page with no network, so the files ship inside the
22 bundle and are bound here. Static instances, one file per weight: a synthesised
23 bold is the failure this avoids, and it fails silently. */
24
25@font-face {
26 font-family: "EB Garamond";
27 src: url("fonts/EB-Garamond/EBGaramond-Regular.otf") format("opentype");
28 font-weight: 400;
29 font-style: normal;
30}
31@font-face {
32 font-family: "EB Garamond";
33 src: url("fonts/EB-Garamond/EBGaramond-Italic.otf") format("opentype");
34 font-weight: 400;
35 font-style: italic;
36}
37@font-face {
38 font-family: "EB Garamond";
39 src: url("fonts/EB-Garamond/EBGaramond-SemiBold.otf") format("opentype");
40 font-weight: 600;
41 font-style: normal;
42}
43@font-face {
44 font-family: "EB Garamond";
45 src: url("fonts/EB-Garamond/EBGaramond-SemiBoldItalic.otf") format("opentype");
46 font-weight: 600;
47 font-style: italic;
48}
49
50@font-face {
51 font-family: "Source Sans 3";
52 src: url("fonts/Source-Sans-3/SourceSans3-300.ttf") format("truetype");
53 font-weight: 300;
54 font-style: normal;
55}
56@font-face {
57 font-family: "Source Sans 3";
58 src: url("fonts/Source-Sans-3/SourceSans3-400.ttf") format("truetype");
59 font-weight: 400;
60 font-style: normal;
61}
62@font-face {
63 font-family: "Source Sans 3";
64 src: url("fonts/Source-Sans-3/SourceSans3-400Italic.ttf") format("truetype");
65 font-weight: 400;
66 font-style: italic;
67}
68@font-face {
69 font-family: "Source Sans 3";
70 src: url("fonts/Source-Sans-3/SourceSans3-600.ttf") format("truetype");
71 font-weight: 600;
72 font-style: normal;
73}
74@font-face {
75 font-family: "Source Sans 3";
76 src: url("fonts/Source-Sans-3/SourceSans3-600Italic.ttf") format("truetype");
77 font-weight: 600;
78 font-style: italic;
79}
80@font-face {
81 font-family: "Source Sans 3";
82 src: url("fonts/Source-Sans-3/SourceSans3-700.ttf") format("truetype");
83 font-weight: 700;
84 font-style: normal;
85}
86
87@font-face {
88 font-family: "IBM Plex Mono";
89 src: url("fonts/IBM-Plex-Mono/IBMPlexMono-400.ttf") format("truetype");
90 font-weight: 400;
91 font-style: normal;
92}
93@font-face {
94 font-family: "IBM Plex Mono";
95 src: url("fonts/IBM-Plex-Mono/IBMPlexMono-400Italic.ttf") format("truetype");
96 font-weight: 400;
97 font-style: italic;
98}
99@font-face {
100 font-family: "IBM Plex Mono";
101 src: url("fonts/IBM-Plex-Mono/IBMPlexMono-600.ttf") format("truetype");
102 font-weight: 600;
103 font-style: normal;
104}
105
106/* --- 2. The page ----------------------------------------------------------
107 Nothing here. The page belongs to the template's own page.css — the letter is
108 A4 at 35mm on all four sides.
109
110 What is worth recording once, rather than twice, is why `@page` is the only
111 mechanism available. iA Writer renders the header and the footer as separate
112 HTML documents and reserves space for them by setting the page margins itself,
113 to the depths given by IATemplateHeaderHeight and IATemplateFooterHeight. A
114 `@page` margin in the template therefore REPLACES those margins rather than
115 adding to them — set both and the band has no space left to draw in, and set
116 `@page { margin: 0 }` and the page loses its top and bottom margins entirely.
117
118 That is why neither template declares a header or a footer, and why neither
119 has a running head or a folio. The specification resolves the running head
120 from the current level-2 heading during layout, which needs a paged-media
121 engine; WebKit implements none of CSS Paged Media, so the band was already
122 only able to show the document title. Losing it costs the title, not the
123 section name. */
124
125/* --- 3. Preview -----------------------------------------------------------
126 In Preview iA Writer sets its own padding on <html> to line the text up with
127 the Editor, so the document page must not add vertical space of its own —
128 this is the one hard instruction in the template documentation. There is no
129 page on screen either, so the margins declared in page.css do not apply and
130 nothing needs to stand in for them. */
131
132@media screen {
133 body.typeset {
134 margin: 0;
135 padding: 0;
136 }
137}
138
139/* iA Writer tints the Preview toolbar from the <html> element's own colours, so
140 they are set on the element rather than inherited up from the body. Literals,
141 not tokens: the tokens are declared on `.typeset`, which is the body.
142
143 Screen only, and the background especially. An <html> background paints the
144 page CONTENT box, not the sheet, so in an export it comes out as a tinted
145 rectangle inset by the page margin with a white border around it — and
146 typeset.css sets `print-color-adjust: exact`, which stops the print pipeline
147 from dropping it to save ink. The paper supplies the ground. */
148@media screen {
149 html {
150 color: #1a1a1a;
151 background-color: #fffefb;
152 }
153}
154
155/* Night mode. Screen only — an export is ink on paper whatever the editor is
156 wearing, and the tokens must stay at their spec values there. */
157@media screen {
158 html.night-mode {
159 color: #d8d4cd;
160 background-color: #1c1c1e;
161 }
162 html.night-mode body.typeset {
163 --ts-ink: #d8d4cd;
164 --ts-ink-muted: #9a958d;
165 --ts-ink-faint: #6f6a64;
166 --ts-rule: #3a3a3c;
167 --ts-rule-strong: #6f6a64;
168 --ts-wash: #2a2a2c;
169 --ts-accent: #d98a8a; /* the oxblood lifted to hold its hue on a dark ground */
170 }
171}
172
173/* --- 4. Footnotes ---------------------------------------------------------
174 A hand-written typeset document marks a note with `.ts-note-marker` and carries
175 the text in `.ts-note-endnotes`. MultiMarkdown emits its own shape instead:
176
177 …text<sup><a class="footnote" href="#fn1" id="fnr1">1</a></sup>…
178 <div class="footnotes"><hr /><ol><li id="fn1">…</li></ol></div>
179
180 The number is real text rather than a counter, so the reference is styled
181 rather than generated. Everything else matches `.ts-note-marker` exactly —
182 `.typeset sup` has already taken the superscript and the zero line-height, so
183 what is left is the colour, the lining figures and the missing underline. */
184
185.typeset sup > a.footnote {
186 font-variant-numeric: lining-nums;
187 text-decoration: none;
188 color: var(--ts-accent);
189}
190
191/* The notes block, styled as `.ts-note-endnotes`. There is deliberately no heading:
192 the rule above it is the only mark it needs. MultiMarkdown supplies that rule
193 as an <hr>, which typeset.css would otherwise set as a `* * *` section break,
194 so it is removed and the border replaces it. */
195.typeset .footnotes {
196 text-align: left;
197 margin-top: calc(var(--ts-space) * 2);
198 padding-top: var(--ts-space);
199 border-top: 0.5pt solid var(--ts-rule);
200 font-size: var(--ts-sm);
201 line-height: 1.4;
202}
203.typeset .footnotes > hr { display: none; }
204.typeset .footnotes ol { padding-left: 1.8em; }
205.typeset .footnotes li { margin-bottom: 0.4em; }
206.typeset .footnotes li > p {
207 margin: 0;
208 text-indent: 0;
209}
210
211/* The back-reference arrow is a Preview affordance. Paper has nothing to click. */
212@media print {
213 .typeset a.reversefootnote { display: none; }
214}
215
216/* A MultiMarkdown citation is set inline rather than as a superscript, and its
217 key is already hidden by an inline style. It reads as a reference, so it takes
218 the reference's colour and loses the underline. */
219.typeset a.citation {
220 text-decoration: none;
221 color: var(--ts-accent);
222 font-variant-numeric: lining-nums;
223}
224
225/* --- 5. Markdown constructs typeset.css does not see ---------------------- */
226
227/* A task list item carries a real checkbox, so typeset's own bullet would sit
228 in front of it. The bullet goes, and the control is redrawn: a printed OS
229 checkbox is a screenshot of an operating system in the middle of a document. */
230.typeset li.task-list-item::before { content: none; }
231.typeset .task-list-item-checkbox {
232 -webkit-appearance: none;
233 appearance: none;
234 float: left;
235 width: 0.66em;
236 height: 0.66em;
237 margin: 0.24em 0 0 -1.4em;
238 padding: 0;
239 border: 0.5pt solid var(--ts-rule-strong);
240 background: none;
241}
242.typeset .task-list-item-checkbox:checked {
243 border-color: var(--ts-ink-muted);
244 background: var(--ts-ink-muted);
245 box-shadow: inset 0 0 0 0.75pt #fffefb;
246}
247
248/* Column alignment is the one thing a Markdown table can state, and it arrives
249 as an inline style on every cell. A right-aligned column is a column of
250 numbers, and a column of numbers only aligns on tabular figures — so the
251 inline style is read as the signal it is. This is what `.ts-table-cell-numeric` does in a
252 hand-written document; the attribute match is the only hook Markdown offers. */
253.typeset th[style*="right"],
254.typeset td[style*="right"] {
255 font-variant-numeric: lining-nums tabular-nums;
256}
257
258/* typeset.css sets the paragraph after a heading, a block or a section break
259 flush left, and enumerates the elements that can precede one. `.ts-break` is
260 in that list; a bare `hr` is not, because a hand-written document writes its
261 breaks as `.ts-break`. Markdown has no such class — `---` is the only section
262 break it can write, and it arrives as an `hr`. Without this the first
263 paragraph after every break is indented, which is the one place it must not be.
264
265 The same is true of a table caption's anchor and of a figure: both already
266 appear in typeset's list. Only `hr` is missing, and only because Markdown
267 reaches it by a different route. */
268.typeset hr + p { text-indent: 0; }
269
270/* MultiMarkdown puts the table caption first in source order. typeset.css
271 already sets `caption-side: top`, so nothing moves; the id anchor a table
272 reference points at needs no styling of its own. */