Release slotifier-1.2.
[homepage.git] / content / style.scss
1 /*!
2  * Nick's web site: default stylesheet
3  *
4  * Copyright © 2018-2021 Nick Bowler
5  *
6  * This program is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
18  */
19
20 // colour definitions
21 $backgroundcolour:  #ffffff;
22 $foregroundcolour:  #000000;
23
24 $linkdefaultcolour: #0000cd;
25 $linkactivecolour:  #ff0000;
26 $linkvisitedcolour: #800080;
27
28 $ruledefaultcolour: #d3d3d3;
29 $rulestrongcolour:  #696969;
30
31 $annotationcolour:  #708090;
32
33 $tableshadecolour:  #f5f5f5;
34
35 @mixin header_size($maxwidth, $fontsize) {
36     font-size: $fontsize;
37     max-width: 1em * ($maxwidth / $fontsize);
38 }
39
40 body {
41     background-color: $backgroundcolour;
42     color: $foregroundcolour;
43     font-family: sans-serif;
44     margin: 1em;
45 }
46
47 a:link { color: $linkdefaultcolour; }
48 a:visited { color: $linkvisitedcolour; }
49 a:active { color: $linkactivecolour; }
50
51 h1 { @include header_size(60em, 2em); }
52 h2 { @include header_size(60em, 1.5em); }
53 h5 { @include header_size(60em, 1em); }
54
55 p>img { max-width: 40em; width: 100%; height: auto; }
56
57 p, dt, dd, li {
58     text-align: justify;
59     @media (max-width: 28em) { text-align: left; }
60     padding: 0;
61     margin: 0;
62 }
63
64 p, table, div, ul, ol, dl, hr {
65     max-width: 50em;
66     padding: 0;
67     margin: 0;
68 }
69
70 p, table, body>div, h5 { margin: 1em 0; }
71 blockquote {
72     @media (max-width: 28em) { margin: 1em 0.5em; }
73     margin: 1em;
74 }
75
76 li { margin: 0 0 0 2em; }
77 dd { margin: 0 0 0 1em; }
78
79 hr {
80     clear: both;
81     margin: 0.5em 0;
82     border: 0;
83     border-top: 1px solid $ruledefaultcolour;
84 }
85
86 kbd {
87     font-family: monospace;
88     font-size: 0.95em;
89     &:before { content: "% "; }
90     &>span { white-space: nowrap; }
91
92     blockquote & {
93         display: block;
94         text-align: left;
95         padding-left: 3em;
96         text-indent: -3em;
97     }
98 }
99
100 .permalink {
101     font-size: small;
102     color: $annotationcolour;
103
104     a:link, a:visited { color: inherit; }
105     @media not screen { visibility: hidden; }
106 }
107
108 // General table styles.
109 table {
110     border: 1px solid $ruledefaultcolour;
111     border-collapse: collapse;
112     width: 100%;
113 }
114
115 table>* { font-size: 0.9em; }
116 caption {
117     caption-side: top;
118     font-weight: bold;
119     font-size: 1em;
120     text-align: left;
121     margin: 0 0 0.5em 0;
122 }
123
124 td, th {
125     vertical-align: middle;
126     text-align: left;
127     padding: 1ex;
128     margin: 0;
129 }
130
131 thead>tr, tbody>tr { border: solid $ruledefaultcolour; }
132 th, thead>tr { border-bottom: 1px solid $rulestrongcolour; }
133 tbody+tbody { border-bottom: 1px solid $ruledefaultcolour; }
134 *>table, *>th { border: none; }
135 thead>tr { border-width: 1px; }
136 tbody>tr { border-width: 0 1px; }
137
138 td + td { box-shadow: -1px 0 $backgroundcolour; }
139
140 tbody>tr {
141     &:nth-of-type(even) { background-color: $tableshadecolour; }
142     &:last-child { border-bottom: solid 1px $ruledefaultcolour; }
143 }
144
145 // Specific table styles
146 table.cc {
147     &>tr>*:first-child, &>*>tr>*:first-child {
148         &+* { text-align: center; }
149         text-align: center;
150     }
151 }
152
153 // CSS rules for stortable clicky table headers: Update the display of
154 // the /table based on the current state.  Each column has its own set
155 // nearly-identical rules, only the class names differ.
156 //
157 // The clickytables.xsl stylesheet generates two inputs for each column.
158 // These inputs are siblings of the table and all precede it in document
159 // order.  Moreover, the inputs for a column are ordered with respect to
160 // each other, in this sequence:
161 //
162 //   input.clicky-NAME     -- checked iff NAME is selected for sorting.
163 //   input.clicky-NAME-rev -- checked to select reverse order.
164 //
165 // One of the column selection inputs will have a 'checked' attribute to
166 // indicate the default order.  This input is always first in document
167 // order.  No other inputs begin checked.
168 //
169 // The table itself consists of a thead (where the header labels are
170 // located) and two tbody elements.  The bulk of these rules relate
171 // to updating the headers to visually indicate the current state.
172 //
173 // A sortable column's th element has the .clicky-NAME class, matching
174 // its corresponding inputs, and has two label children.  The first label
175 // is visible only when the column is unselected, and is linked to the
176 // .clicky-NAME input to activate that column.  The second label is visible
177 // only on the selected column and is linked to the .clicky-NAME-rev input
178 // to toggle the reverse order.
179 //
180 // For the table body, the first tbody contains the default ordering
181 // and is not styled by these rules (except to hide it when alternate
182 // orderings are selected).  The second tbody contains rows for all
183 // alternate orderings, and is revealed by these rules.  When revealed,
184 // rows with the NAMEfwd or NAMErev class (for the forward and reverse
185 // orderings, respectively) are shown and other rows are hidden.
186
187 $clickynames: name, date, size;
188 @each $col in $clickynames {
189     input.clicky-#{$col} {
190         &:checked {
191             &~table {
192                 // Update table header state
193                 & th.clicky-#{$col} {
194                     label~label {
195                         display: -moz-inline-box !important;
196                         display: inline-block !important;
197                     }
198                     label { display: none; }
199                 }
200
201                 // Show only appropriate items from the sort body (forward)
202                 &>tbody+tbody>tr.#{$col}fwd { display: table-row; }
203                 &>tbody+tbody>tr { display: none; }
204
205                 // Unhide sort body
206                 &>tbody {
207                     &+tbody { display: table-row-group !important; }
208                     display: none;
209                 }
210             }
211
212             // reverse state for selected sort column
213             &~input.clicky-#{$col}-rev {
214                 &:checked ~ table {
215                     // Show only appropriate items from sort body (reversed)
216                     &>tbody+tbody>tr.#{$col}rev { display: table-row; }
217                     &>tbody+tbody>tr { display: none; }
218
219                     // Unhide sort body
220                     &>tbody {
221                         &+tbody { display: table-row-group !important; }
222                         display: none;
223                     }
224                 }
225
226                 // Unhide to allow keyboard navigation to this input
227                 display: block !important;
228             }
229         }
230
231         // If default input element is the only one selected, match it to
232         // return to default view (overriding the changes above).  It is
233         // always the first input element among all the sibling elements.
234         // This seems to interoperate better than using the [checked] or
235         // :first-of-type selectors.
236         @at-root &:first-child, :not(input)+& {
237             &:checked~table>tbody {
238                 &+tbody { display: none !important; }
239                 display: table-row-group;
240             }
241         }
242
243         &:focus ~ table th.clicky-#{$col}>label~label>span:first-child {
244             border-color: $foregroundcolour;
245         }
246
247         // Unhide to allow keyboard navigation
248         display: block !important;
249         pointer-events: none;
250         position: absolute;
251         opacity: 0;
252         z-index: -1;
253     }
254
255     input.clicky-#{$col}-rev {
256         &:checked ~ table {
257             // Update table header state
258             & th.clicky-#{$col} {
259                 .svg+.svg {
260                     display: -moz-inline-box !important;
261                     display: inline-block !important;
262                 }
263                 .svg { display: none; }
264             }
265         }
266
267         &:focus ~ table th.clicky-#{$col}>label~label .svg {
268             border-color: $foregroundcolour;
269         }
270
271         pointer-events: none;
272         position: absolute;
273         opacity: 0;
274         z-index: -2;
275     }
276 }
277
278 thead.clicky label {
279     white-space: nowrap;
280     line-height: 1.5em;
281     cursor: pointer;
282
283     &>* {
284         display: -moz-inline-box;
285         display: inline-block;
286         border: 1px dotted transparent;
287         vertical-align: middle;
288     }
289
290     // Expand the first label a bit so the table (hopefully)
291     // does not reshape as columns are selected.
292     &:first-child {
293         margin-right: 1.75em;
294         padding-right: 2px;
295     }
296
297     &:active { color: $linkactivecolour; }
298     &:first-child:active>span, &~label:active>.svg {
299         border-color: $linkactivecolour;
300     }
301
302     .svg {
303         margin-left: 0.25em;
304     }
305
306     .svg, svg, img.svgfallback {
307         height: 1.5em;
308         width: auto;
309     }
310     .svg svg { width: 1.5em; }
311 }
312
313 table.filelist {
314     &>*>tr>*:first-child {
315         &+* { width: 50%; }
316         // chrome doesn't like width: 0 for some reason
317         width: 0.1px;
318     }
319
320     tbody {
321         .svg, svg, img.svgfallback {
322             vertical-align: middle;
323             height: 1.5em;
324             width: auto;
325         }
326
327         .svg {
328             svg { width: 1.5em; }
329             display: inline-block;
330         }
331     }
332 }
333
334 // Site header rules
335 #breadcrumbs>*, #sitetitle>* { font-size: 0.8em; }
336 #breadcrumbs {
337     * {
338         display: inline;
339         list-style-type: none;
340         vertical-align: top;
341         padding: 0;
342         margin: 0;
343     }
344
345     li + li:before { content: "/ "; }
346 }
347 #sitetitle * {
348     display: inline-block;
349     float: right;
350 }
351
352 // Site footer rules
353 #footer, #article-info {
354     text-align: center;
355     max-width: 44em;
356     padding: 0 3em;
357     margin: 0;
358
359     p {
360         display: inline-block;
361         font-size: 0.8em;
362         max-width: 100%;
363         margin: 0.2em 0;
364     }
365 }
366
367 #footer p { color: $annotationcolour; }
368 #article-info p { font-style: italic; }
369
370 .wbr:after { content: "\200b"; }
371
372 // "unordered" lists with explicit ordering in content
373 ul.ordered > {
374     li { list-style: none; }
375     li>span:first-child, li>*:first-child>span:first-child {
376         display: inline-block;
377         text-align: right;
378         margin-left: -1.8em;
379         min-width: 1.8em;
380     }
381 }
382
383 @media (max-width: 512px) {
384     body { margin: 0.6em; }
385     ul ul { margin-left: -1.2em; }
386     dd { margin: 0; }
387 }
388
389 @media (max-width: 35em) {
390     #sitetitle * { float: none; }
391     #footer { padding: 0 1em; }
392 }