Simplify footer text when everything is identical.
[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; border-color: $linkdefaultcolour; }
48 a:visited { color: $linkvisitedcolour; border-color: $linkvisitedcolour; }
49 a:active { color: $linkactivecolour; border-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 @supports (display: grid) {
56     .gallery {
57         display: grid;
58         grid-column-gap: 1em;
59         grid-template-columns: repeat( auto-fill, minmax(18em, 1fr) );
60         align-items: center;
61
62         p.img { margin: 0.5em 0; }
63     }
64 }
65
66 p.img {
67     text-align: center;
68
69     img {
70         vertical-align: bottom;
71         max-width: 40em;
72         width: 100%;
73         height: auto;
74     }
75
76     a {
77         text-decoration: none;
78         display: inline-block;
79         border: solid 2px;
80     }
81
82     small {
83         color: $foregroundcolour;
84         text-align: justify;
85         @media (max-width: 24em) { text-align: left; }
86         padding: 0.5ex;
87         display: block;
88         font-size: 0.9em;
89     }
90 }
91
92 p, dt, dd, li {
93     text-align: justify;
94     @media (max-width: 28em) { text-align: left; }
95     padding: 0;
96     margin: 0;
97 }
98
99 p, table, div, ul, ol, dl, hr {
100     max-width: 50em;
101     padding: 0;
102     margin: 0;
103 }
104
105 p, table, body>div, h5 { margin: 1em 0; }
106 blockquote {
107     @media (max-width: 28em) { margin: 1em 0.5em; }
108     margin: 1em;
109 }
110
111 li { margin: 0 0 0 2em; }
112 dd { margin: 0 0 0 1em; }
113
114 hr {
115     clear: both;
116     margin: 0.5em 0;
117     border: 0;
118     border-top: 1px solid $ruledefaultcolour;
119 }
120
121 kbd {
122     font-family: monospace;
123     font-size: 0.95em;
124     &:before { content: "% "; }
125     &>span { white-space: nowrap; }
126
127     blockquote & {
128         display: block;
129         text-align: left;
130         padding-left: 3em;
131         text-indent: -3em;
132     }
133 }
134
135 .permalink {
136     font-size: small;
137     color: $annotationcolour;
138
139     a:link, a:visited { color: inherit; }
140     @media not screen { visibility: hidden; }
141 }
142
143 // General table styles.
144 table {
145     border: 1px solid $ruledefaultcolour;
146     border-collapse: collapse;
147     width: 100%;
148 }
149
150 table>* { font-size: 0.9em; }
151 caption {
152     caption-side: top;
153     font-weight: bold;
154     font-size: 1em;
155     text-align: left;
156     margin: 0 0 0.5em 0;
157 }
158
159 td, th {
160     vertical-align: middle;
161     text-align: left;
162     padding: 1ex;
163     margin: 0;
164 }
165
166 thead>tr, tbody>tr { border: solid $ruledefaultcolour; }
167 th, thead>tr { border-bottom: 1px solid $rulestrongcolour; }
168 tbody+tbody { border-bottom: 1px solid $ruledefaultcolour; }
169 *>table, *>th { border: none; }
170 thead>tr { border-width: 1px; }
171 tbody>tr { border-width: 0 1px; }
172
173 td + td { box-shadow: -1px 0 $backgroundcolour; }
174
175 tbody>tr {
176     &:nth-of-type(even) { background-color: $tableshadecolour; }
177     &:last-child { border-bottom: solid 1px $ruledefaultcolour; }
178 }
179
180 // Specific table styles
181 table.cc {
182     &>tr>*:first-child, &>*>tr>*:first-child {
183         &+* { text-align: center; }
184         text-align: center;
185     }
186 }
187
188 // CSS rules for stortable clicky table headers: Update the display of
189 // the /table based on the current state.  Each column has its own set
190 // nearly-identical rules, only the class names differ.
191 //
192 // The clickytables.xsl stylesheet generates two inputs for each column.
193 // These inputs are siblings of the table and all precede it in document
194 // order.  Moreover, the inputs for a column are ordered with respect to
195 // each other, in this sequence:
196 //
197 //   input.clicky-NAME     -- checked iff NAME is selected for sorting.
198 //   input.clicky-NAME-rev -- checked to select reverse order.
199 //
200 // One of the column selection inputs will have a 'checked' attribute to
201 // indicate the default order.  This input is always first in document
202 // order.  No other inputs begin checked.
203 //
204 // The table itself consists of a thead (where the header labels are
205 // located) and two tbody elements.  The bulk of these rules relate
206 // to updating the headers to visually indicate the current state.
207 //
208 // A sortable column's th element has the .clicky-NAME class, matching
209 // its corresponding inputs, and has two label children.  The first label
210 // is visible only when the column is unselected, and is linked to the
211 // .clicky-NAME input to activate that column.  The second label is visible
212 // only on the selected column and is linked to the .clicky-NAME-rev input
213 // to toggle the reverse order.
214 //
215 // For the table body, the first tbody contains the default ordering
216 // and is not styled by these rules (except to hide it when alternate
217 // orderings are selected).  The second tbody contains rows for all
218 // alternate orderings, and is revealed by these rules.  When revealed,
219 // rows with the NAMEfwd or NAMErev class (for the forward and reverse
220 // orderings, respectively) are shown and other rows are hidden.
221
222 $clickynames: name, date, size;
223 @each $col in $clickynames {
224     input.clicky-#{$col} {
225         &:checked {
226             &~table {
227                 // Update table header state
228                 & th.clicky-#{$col} {
229                     label~label {
230                         display: -moz-inline-box !important;
231                         display: inline-block !important;
232                     }
233                     label { display: none; }
234                 }
235
236                 // Show only appropriate items from the sort body (forward)
237                 &>tbody+tbody>tr.#{$col}fwd { display: table-row; }
238                 &>tbody+tbody>tr { display: none; }
239
240                 // Unhide sort body
241                 &>tbody {
242                     &+tbody { display: table-row-group !important; }
243                     display: none;
244                 }
245             }
246
247             // reverse state for selected sort column
248             &~input.clicky-#{$col}-rev {
249                 &:checked ~ table {
250                     // Show only appropriate items from sort body (reversed)
251                     &>tbody+tbody>tr.#{$col}rev { display: table-row; }
252                     &>tbody+tbody>tr { display: none; }
253
254                     // Unhide sort body
255                     &>tbody {
256                         &+tbody { display: table-row-group !important; }
257                         display: none;
258                     }
259                 }
260
261                 // Unhide to allow keyboard navigation to this input
262                 display: block !important;
263             }
264         }
265
266         // If default input element is the only one selected, match it to
267         // return to default view (overriding the changes above).  It is
268         // always the first input element among all the sibling elements.
269         // This seems to interoperate better than using the [checked] or
270         // :first-of-type selectors.
271         @at-root &:first-child, :not(input)+& {
272             &:checked~table>tbody {
273                 &+tbody { display: none !important; }
274                 display: table-row-group;
275             }
276         }
277
278         &:focus ~ table th.clicky-#{$col}>label~label>span:first-child {
279             border-color: $foregroundcolour;
280         }
281
282         // Unhide to allow keyboard navigation
283         display: block !important;
284         pointer-events: none;
285         position: absolute;
286         opacity: 0;
287         z-index: -1;
288     }
289
290     input.clicky-#{$col}-rev {
291         &:checked ~ table {
292             // Update table header state
293             & th.clicky-#{$col} {
294                 .svg+.svg {
295                     display: -moz-inline-box !important;
296                     display: inline-block !important;
297                 }
298                 .svg { display: none; }
299             }
300         }
301
302         &:focus ~ table th.clicky-#{$col}>label~label .svg {
303             border-color: $foregroundcolour;
304         }
305
306         pointer-events: none;
307         position: absolute;
308         opacity: 0;
309         z-index: -2;
310     }
311 }
312
313 thead.clicky label {
314     white-space: nowrap;
315     line-height: 1.5em;
316     cursor: pointer;
317
318     &>* {
319         display: -moz-inline-box;
320         display: inline-block;
321         border: 1px dotted transparent;
322         vertical-align: middle;
323     }
324
325     // Expand the first label a bit so the table (hopefully)
326     // does not reshape as columns are selected.
327     &:first-child {
328         margin-right: 1.75em;
329         padding-right: 2px;
330     }
331
332     &:active { color: $linkactivecolour; }
333     &:first-child:active>span, &~label:active>.svg {
334         border-color: $linkactivecolour;
335     }
336
337     .svg {
338         margin-left: 0.25em;
339     }
340
341     .svg, svg, img.svgfallback {
342         height: 1.5em;
343         width: auto;
344     }
345     .svg svg { width: 1.5em; }
346 }
347
348 table.filelist {
349     &>*>tr>*:first-child {
350         &+* { width: 50%; }
351         // chrome doesn't like width: 0 for some reason
352         width: 0.1px;
353     }
354
355     tbody {
356         .svg, svg, img.svgfallback {
357             vertical-align: middle;
358             height: 1.5em;
359             width: auto;
360         }
361
362         .svg {
363             svg { width: 1.5em; }
364             display: inline-block;
365         }
366     }
367 }
368
369 // Site header rules
370 #breadcrumbs>*, #sitetitle>* { font-size: 0.8em; }
371 #breadcrumbs {
372     * {
373         display: inline;
374         list-style-type: none;
375         vertical-align: top;
376         padding: 0;
377         margin: 0;
378     }
379
380     li + li:before { content: "/ "; }
381 }
382 #sitetitle * {
383     display: inline-block;
384     float: right;
385 }
386
387 // Site footer rules
388 #footer, #article-info {
389     text-align: center;
390     max-width: 44em;
391     padding: 0 3em;
392     margin: 0;
393
394     p {
395         display: inline-block;
396         font-size: 0.8em;
397         max-width: 100%;
398         margin: 0.2em 0;
399     }
400 }
401
402 #footer p { color: $annotationcolour; }
403 #article-info p { font-style: italic; }
404
405 .wbr:after { content: "\200b"; }
406
407 // "unordered" lists with explicit ordering in content
408 ul.ordered > {
409     li { list-style: none; }
410     li>span:first-child, li>*:first-child>span:first-child {
411         display: inline-block;
412         text-align: right;
413         margin-left: -1.8em;
414         min-width: 1.8em;
415     }
416 }
417
418 @media (max-width: 512px) {
419     body { margin: 0.6em; }
420     ul ul { margin-left: -1.2em; }
421     dd { margin: 0; }
422 }
423
424 @media (max-width: 35em) {
425     #sitetitle * { float: none; }
426     #footer { padding: 0 1em; }
427 }