-
-
+
Address
@@ -259,9 +252,9 @@ Address
-
+
-
+
Email
@@ -271,7 +264,7 @@ Email
-
+
diff --git a/css/style.css b/css/style.css
index 47183d8..fe7f6c8 100644
--- a/css/style.css
+++ b/css/style.css
@@ -28,32 +28,33 @@
/*--------------------------------------------------------------------------
Web font
- Roboto Slab, self-hosted. The template used to pull this from
+ Inter, self-hosted. The template used to pull its web font from
fonts.googleapis.com over plain HTTP, which meant a blocked request on
any HTTPS site, two extra DNS lookups and connections on every page
load, and a visitor IP address handed to a third party.
- One variable file covers both weights the design uses. Licence in
- fonts/LICENSE.txt (Apache 2.0).
+ One variable file covers every weight the design uses, from the 300 of
+ the display lines to the 800 of the wordmark. Licence in
+ fonts/LICENSE.txt (SIL Open Font License 1.1).
--------------------------------------------------------------------------*/
@font-face {
- font-family: "Roboto Slab";
+ font-family: "Inter";
font-style: normal;
- font-weight: 300 400;
+ font-weight: 100 900;
font-display: swap;
- src: url("../fonts/roboto-slab-latin.woff2") format("woff2");
+ src: url("../fonts/inter-latin.woff2") format("woff2");
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6,
U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122,
U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
- font-family: "Roboto Slab";
+ font-family: "Inter";
font-style: normal;
- font-weight: 300 400;
+ font-weight: 100 900;
font-display: swap;
- src: url("../fonts/roboto-slab-latin-ext.woff2") format("woff2");
+ src: url("../fonts/inter-latin-ext.woff2") format("woff2");
unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7,
U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F,
U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F,
@@ -99,6 +100,16 @@
--color-on-panel: #fff;
--color-panel-rule: #2a2a2a;
+ /*
+ The dropdown menu has its own surface rather than borrowing the dark
+ panel. A black block stamped over the page every time the pointer
+ crossed the bar; this sits just far enough off the page to read as a
+ panel and no further.
+ */
+ --color-menu: #f4f4f4;
+ --color-on-menu: #111;
+ --color-menu-rule: #e4e4e4;
+
/* The stage a photograph sits on. Always dark, in both themes. */
--color-stage: #111;
--color-on-stage: #fff;
@@ -126,9 +137,24 @@
has to stay dark in both themes (13:1 against the accent). */
--color-on-accent: #111;
- /* Type */
- --font-sans: "Helvetica Neue", Helvetica, Arial, system-ui, sans-serif;
- --font-serif: "Roboto Slab", Georgia, "Times New Roman", serif;
+ /* Type
+
+ One family sets the whole template. Inter is drawn a touch wide for
+ its own defaults, so everything is tracked in slightly: a little at
+ text sizes, more on display lines, which need less air the larger
+ they get. */
+ --font-sans: "Inter", system-ui, -apple-system, "Segoe UI", Arial, sans-serif;
+ --tracking-text: -0.011em;
+ --tracking-display: -0.022em;
+ --tracking-wordmark: -0.05em;
+
+ /* Icons
+
+ Lucide chevrons (https://lucide.dev, ISC), inlined as masks so they
+ take the colour of the text they sit next to, in either theme, and
+ cost no request. */
+ --icon-chevron-down: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
+ --icon-chevron-right: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m9 18 6-6-6-6'/%3E%3C/svg%3E");
/* Motion */
--transition-fast: 150ms ease;
@@ -163,6 +189,12 @@
--color-on-panel: #f2f2f2;
--color-panel-rule: #383838;
+ /* Same idea the other way up: one step off the page, not a white
+ sheet dropped over it. */
+ --color-menu: #1d1d1d;
+ --color-on-menu: #f2f2f2;
+ --color-menu-rule: #303030;
+
--color-stage: #000;
--color-danger: #ff7a60;
@@ -183,9 +215,11 @@ body {
font-family: var(--font-sans);
/* Scales smoothly between phone and desktop instead of stepping at a
- single breakpoint. */
- font-size: clamp(0.8125rem, 0.72rem + 0.4vw, 0.875rem);
+ single breakpoint. The floor is 14px: nothing in the template is set
+ smaller than that. */
+ font-size: clamp(0.875rem, 0.7825rem + 0.4vw, 0.9375rem);
line-height: 1.85;
+ letter-spacing: var(--tracking-text);
}
@@ -263,7 +297,7 @@ p a:visited { line-height: inherit; }
padding: 12px 20px;
color: var(--color-on-panel);
background: var(--color-panel);
- font-size: 13px;
+ font-size: 14px;
font-weight: bold;
transform: translateY(-120%);
transition: transform var(--transition-fast);
@@ -354,16 +388,24 @@ b, strong { font-weight: bold; }
.post img.featured { margin-bottom: 50px; }
- /* Buttons */
- button,
+ /*
+ Buttons
+
+ Scoped to the .button class rather than the bare
element.
+ The slider arrows, the thumbnail strip and the labelled project nav
+ are real buttons that carry their own look; as an element selector
+ this skin's :hover rule outranked their `background: none` and filled
+ them with accent whenever the pointer passed over.
+ */
.button,
a.button {
color: var(--color-on-accent);
background: var(--color-accent);
font-size: 14px;
+ line-height: 20px;
font-weight: bold;
text-align: center;
- padding: 20px 25px 18px 25px;
+ padding: 13px 24px 12px 24px;
border: 0;
border-bottom: 2px solid var(--color-accent-hover);
transition: background var(--transition-fast);
@@ -373,30 +415,28 @@ b, strong { font-weight: bold; }
border-radius: 4px;
}
- button.small,
.button.small,
a.button.small {
font-size: 14px;
- line-height: 24px;
- padding: 16px 24px;
+ line-height: 20px;
+ padding: 9px 18px 8px 18px;
border-radius: 3px;
}
- button.full,
+ /* The full-width call to action. Taller than the inline button, but
+ sized to its label rather than to the column it happens to fill. */
.button.full,
a.button.full {
display: block;
width: 100%;
border-radius: 5px;
- padding: 30px 40px 26px 40px;
- border-bottom: 4px solid var(--color-accent-hover);
+ padding: 17px 32px 16px 32px;
+ border-bottom: 3px solid var(--color-accent-hover);
}
- button:hover,
.button:hover,
a.button:hover { background: var(--color-accent-hover); }
- button.black,
.button.black,
a.button.black {
color: var(--color-on-panel);
@@ -404,7 +444,6 @@ b, strong { font-weight: bold; }
border-color: var(--color-text);
}
- button.black:hover,
.button.black:hover,
a.button.black:hover {
color: var(--color-accent-invert);
@@ -423,7 +462,7 @@ b, strong { font-weight: bold; }
label {
display: block;
color: var(--color-text);
- font-size: 13px;
+ font-size: 14px;
line-height: 23px;
margin: 20px 0;
}
@@ -486,8 +525,8 @@ b, strong { font-weight: bold; }
.page p.page-desc {
color: var(--color-text);
- font-family: var(--font-serif);
font-size: 34px;
+ letter-spacing: var(--tracking-display);
line-height: 60px;
font-weight: 300;
margin-top: 30px;
@@ -539,7 +578,7 @@ b, strong { font-weight: bold; }
/* Page Navigation */
.nav-pages {
- font-size: 11px;
+ font-size: 14px;
margin-top: 30px;
}
@@ -610,15 +649,11 @@ b, strong { font-weight: bold; }
ul#nav {
display: flex;
flex-wrap: wrap;
- font-size: 12px;
+ font-size: 14px;
line-height: 21px;
font-weight: bold;
}
- @media screen and (min-width: 768px) and (max-width: 959px) {
- ul#nav { font-size: 11px; }
- }
-
/*
Hide the whole bar, not just the list. Leaving an empty behind
put two navigation landmarks with the same name in the accessibility
@@ -634,38 +669,31 @@ b, strong { font-weight: bold; }
ul#nav > li > a {
color: var(--color-text-subtle);
- display: block;
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ gap: 8px;
padding: 18px 0 15px 0;
margin: 0 20px;
border-bottom: 1px solid var(--color-rule);
transition: color var(--transition-fast);
}
- ul#nav > li > a span.count {
- color: var(--color-text-subtle);
- display: block;
- font-size: 11px;
- }
-
ul#nav > li:hover,
ul#nav > li:focus-within,
ul#nav > li.hover {
- background: var(--color-panel);
+ background: var(--color-menu);
}
ul#nav > li:hover > a,
ul#nav > li:focus-within > a,
ul#nav > li.hover > a {
- color: var(--color-on-panel);
+ color: var(--color-on-menu);
border-bottom-color: transparent;
margin: 0;
padding-inline: 20px;
}
- ul#nav > li:hover > a span.count,
- ul#nav > li:focus-within > a span.count,
- ul#nav > li.hover > a span.count { color: var(--color-on-panel); }
-
/*
Parent items keep a hairline under the label so the open submenu
reads as attached. :has() finds them in CSS; the old build needed a
@@ -675,11 +703,12 @@ b, strong { font-weight: bold; }
ul#nav > li:has(> ul):focus-within > a,
ul#nav > li.hasChild:hover > a,
ul#nav > li.hasChild:focus-within > a,
- ul#nav > li.hasChild.hover > a { border-bottom-color: var(--color-panel-rule); }
+ ul#nav > li.hasChild.hover > a { border-bottom-color: var(--color-menu-rule); }
/* Submenus */
ul#nav li ul {
- background: var(--color-panel);
+ background: var(--color-menu);
+ box-shadow: 0 14px 28px rgb(0 0 0 / 0.07);
width: 100%;
min-width: 11rem;
position: absolute;
@@ -699,20 +728,48 @@ b, strong { font-weight: bold; }
}
ul#nav li ul a {
- color: var(--color-on-panel);
- display: block;
+ color: var(--color-on-menu);
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ gap: 8px;
padding: 18px 20px;
- border-bottom: 1px solid var(--color-panel-rule);
+ border-bottom: 1px solid var(--color-menu-rule);
transition: color var(--transition-fast);
}
ul#nav li ul a:hover,
ul#nav li ul a:focus-visible {
- color: var(--color-accent-invert);
+ color: var(--color-accent-text);
}
ul#nav li ul li:last-child > a { border-bottom: none; }
+ /*
+ Parent items carry a chevron at the far right of their own row:
+ down for a submenu below, right for one that opens sideways. The
+ script used to append a ▾ and a ▸ text node; a masked icon keeps
+ the shape a real chevron at any size and leaves the menu markup
+ alone, which is also what the phone menu is cloned from.
+ */
+ ul#nav > li:has(> ul) > a::after,
+ ul#nav > li.hasChild > a::after,
+ ul#nav li ul li:has(> ul) > a::after,
+ ul#nav li ul li.hasChild > a::after {
+ content: "";
+ flex: none;
+ width: 16px;
+ height: 16px;
+ background-color: currentColor;
+ mask-image: var(--icon-chevron-down);
+ mask-repeat: no-repeat;
+ mask-position: center;
+ mask-size: contain;
+ }
+
+ ul#nav li ul li:has(> ul) > a::after,
+ ul#nav li ul li.hasChild > a::after { mask-image: var(--icon-chevron-right); }
+
/* Third level opens sideways, flipping in before it leaves the viewport. */
ul#nav > li ul ul {
top: 0;
@@ -793,7 +850,7 @@ b, strong { font-weight: bold; }
#menu-mobile-wrapper ul#menu-mobile.is-open { display: block; }
#menu-mobile-wrapper ul#menu-mobile li {
- font-size: 12px;
+ font-size: 14px;
line-height: 21px;
display: block;
}
@@ -820,15 +877,44 @@ b, strong { font-weight: bold; }
#header .logo-wrap { padding: 50px 0 50px 0; }
- #header h1 {
- font-size: 24px;
- line-height: 34px;
- font-weight: bold;
+ /*
+ The wordmark. It used to be a 764px PNG, which meant a request, a
+ fetchpriority hint, and an invert filter to keep it visible in dark
+ mode. As text it is sharp at any size and takes its colour from the
+ theme like everything else.
+
+ Sized in cqw against its own column, so it fills the header the way
+ the bitmap did at every width instead of stepping at breakpoints.
+ */
+ #header h1.site-title {
+ container-type: inline-size;
+ font-weight: 800;
}
+ #header h1.site-title a {
+ display: inline-flex;
+ align-items: flex-start;
+ color: var(--color-text);
+ font-size: 28cqw;
+ line-height: 0.82;
+ letter-spacing: var(--tracking-wordmark);
+ text-transform: uppercase;
+ }
+
+ /* The ring the original artwork set over the last letter. */
+ #header h1.site-title .wordmark-ring {
+ flex: none;
+ width: 0.21em;
+ height: 0.21em;
+ margin-top: 0.04em;
+ margin-left: 0.05em;
+ border: 0.042em solid currentColor;
+ border-radius: 50%;
+ }
+
#header p.site-desc {
color: var(--color-text-subtle);
- font-size: 12px;
+ font-size: 14px;
line-height: 19px;
}
@@ -893,8 +979,8 @@ b, strong { font-weight: bold; }
.box-about h3 { margin-bottom: 50px; }
.box-about p.tagline {
- font-family: var(--font-serif);
font-size: 24px;
+ letter-spacing: var(--tracking-display);
line-height: 44px;
font-weight: 300;
margin-top: 30px;
@@ -942,7 +1028,7 @@ b, strong { font-weight: bold; }
}
#about .services p {
- font-size: 12px;
+ font-size: 14px;
line-height: 24px;
}
}
@@ -956,7 +1042,7 @@ b, strong { font-weight: bold; }
#works .item h3 {
color: var(--color-text-muted);
- font-size: 12px;
+ font-size: 14px;
line-height: 22px;
font-weight: bold;
}
@@ -966,7 +1052,7 @@ b, strong { font-weight: bold; }
#works .item span.category {
color: var(--color-text-subtle);
display: block;
- font-size: 12px;
+ font-size: 14px;
line-height: 18px;
margin-bottom: 10px;
}
@@ -974,7 +1060,7 @@ b, strong { font-weight: bold; }
#works a.permalink:hover span.category { color: var(--color-accent-text); }
#works .item p.excerpt {
- font-size: 13px;
+ font-size: 14px;
line-height: 18px;
margin-top: 10px;
}
@@ -1079,7 +1165,7 @@ b, strong { font-weight: bold; }
}
#works.single .box-info h4 {
- font-size: 11px;
+ font-size: 14px;
line-height: 21px;
text-transform: uppercase;
letter-spacing: 3px;
@@ -1095,7 +1181,7 @@ b, strong { font-weight: bold; }
@media screen and (max-width: 767px) {
#works.single .box-info p {
- font-size: 12px;
+ font-size: 14px;
line-height: 24px;
}
}
@@ -1115,7 +1201,7 @@ b, strong { font-weight: bold; }
#shop .shop-info p {
color: var(--color-text);
- font-size: 13px;
+ font-size: 14px;
line-height: 26px;
margin-top: 20px;
}
@@ -1133,7 +1219,7 @@ b, strong { font-weight: bold; }
#shop .cart-item {
- font-size: 12px;
+ font-size: 14px;
line-height: 22px;
margin-bottom: 40px;
}
@@ -1191,7 +1277,7 @@ b, strong { font-weight: bold; }
@media screen and (max-width: 767px) {
#shop .cart-item {
- font-size: 11px;
+ font-size: 14px;
line-height: 21px;
}
@@ -1366,7 +1452,7 @@ b, strong { font-weight: bold; }
#checkout label {
display: block;
color: var(--color-text);
- font-size: 13px;
+ font-size: 14px;
line-height: 23px;
margin: 10px 0 6px 0;
}
@@ -1435,7 +1521,7 @@ b, strong { font-weight: bold; }
#archive .box-meta span.category,
#archive .box-meta span.date {
color: var(--color-text-subtle);
- font-size: 12px;
+ font-size: 14px;
line-height: 22px;
}
@@ -1452,8 +1538,8 @@ b, strong { font-weight: bold; }
}
#archive .entry h3 {
- font-family: var(--font-serif);
font-size: 26px;
+ letter-spacing: var(--tracking-display);
line-height: 40px;
font-weight: 300;
margin-bottom: 28px;
@@ -1476,7 +1562,7 @@ b, strong { font-weight: bold; }
#archive .entry p.tags {
- font-size: 12px;
+ font-size: 14px;
line-height: 22px;
margin-top: 0;
}
@@ -1496,7 +1582,7 @@ b, strong { font-weight: bold; }
@media screen and (max-width: 959px) {
#archive .entry p {
- font-size: 13px;
+ font-size: 14px;
line-height: 25px;
}
@@ -1510,8 +1596,8 @@ b, strong { font-weight: bold; }
}
#archive .entry blockquote p {
- font-family: var(--font-serif);
font-size: 36px;
+ letter-spacing: var(--tracking-display);
line-height: 60px;
font-style: italic;
font-weight: 300;
@@ -1520,7 +1606,7 @@ b, strong { font-weight: bold; }
#archive .entry blockquote footer {
color: var(--color-accent-text);
- font-size: 12px;
+ font-size: 14px;
line-height: 22px;
font-style: italic;
display: inline-block;
@@ -1580,7 +1666,7 @@ b, strong { font-weight: bold; }
@media screen and (max-width: 767px) {
section#contact .box-contact {
- font-size: 12px;
+ font-size: 14px;
line-height: 24px;
margin-bottom: 30px;
}
@@ -1588,7 +1674,7 @@ b, strong { font-weight: bold; }
@media screen and (max-width: 479px) {
section#contact .box-contact {
- font-size: 11px;
+ font-size: 14px;
line-height: 22px;
}
}
@@ -1610,7 +1696,7 @@ b, strong { font-weight: bold; }
section#contact p.map-link {
margin: 0 0 30px 0;
- font-size: 12px;
+ font-size: 14px;
}
section#contact p.map-link a {
@@ -1643,7 +1729,7 @@ b, strong { font-weight: bold; }
---------------------------------------------------*/
#footer {
- font-size: 13px;
+ font-size: 14px;
line-height: 24px;
padding: 30px 0;
}
@@ -1729,6 +1815,21 @@ b, strong { font-weight: bold; }
.tf-slider__track::-webkit-scrollbar { display: none; }
+ /*
+ The script marks the track draggable once it is running, so the
+ grab cursor only appears where a drag will actually do something.
+ Snapping is switched off for the length of a drag: mandatory
+ snapping fights a scrollLeft written by hand, pixel by pixel.
+ */
+ .tf-slider__track.is-draggable { cursor: grab; }
+
+ .tf-slider__track.is-dragging {
+ cursor: grabbing;
+ scroll-snap-type: none;
+ scroll-behavior: auto;
+ user-select: none;
+ }
+
@media (prefers-reduced-motion: reduce) {
.tf-slider__track { scroll-behavior: auto; }
}
@@ -1911,7 +2012,7 @@ b, strong { font-weight: bold; }
.item-nav span.category {
display: inline-block;
color: var(--color-on-stage-muted);
- font-size: 11px;
+ font-size: 14px;
line-height: 21px;
text-transform: uppercase;
letter-spacing: 2px;
@@ -1928,3 +2029,20 @@ b, strong { font-weight: bold; }
color: var(--color-on-stage);
border-top-color: var(--color-accent);
}
+
+
+ /*
+ Focus ring for the controls that sit flush inside a dark strip.
+
+ The shared ring is drawn 3px outside the element, which here either
+ spills past the panel onto the page or is clipped away by the
+ thumbnail strip's own scrolling box. The light-mode ring colour is
+ also too dark to read against the panel. So: bright accent, drawn
+ inside the control.
+ */
+ .slider-thumbs button:focus-visible,
+ .item-nav:focus-visible {
+ outline: 2px solid var(--color-accent);
+ outline-offset: -2px;
+ border-radius: 0;
+ }
diff --git a/fonts/LICENSE.txt b/fonts/LICENSE.txt
index d645695..9b2ca37 100644
--- a/fonts/LICENSE.txt
+++ b/fonts/LICENSE.txt
@@ -1,202 +1,92 @@
-
- Apache License
- Version 2.0, January 2004
- http://www.apache.org/licenses/
-
- TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
- 1. Definitions.
-
- "License" shall mean the terms and conditions for use, reproduction,
- and distribution as defined by Sections 1 through 9 of this document.
-
- "Licensor" shall mean the copyright owner or entity authorized by
- the copyright owner that is granting the License.
-
- "Legal Entity" shall mean the union of the acting entity and all
- other entities that control, are controlled by, or are under common
- control with that entity. For the purposes of this definition,
- "control" means (i) the power, direct or indirect, to cause the
- direction or management of such entity, whether by contract or
- otherwise, or (ii) ownership of fifty percent (50%) or more of the
- outstanding shares, or (iii) beneficial ownership of such entity.
-
- "You" (or "Your") shall mean an individual or Legal Entity
- exercising permissions granted by this License.
-
- "Source" form shall mean the preferred form for making modifications,
- including but not limited to software source code, documentation
- source, and configuration files.
-
- "Object" form shall mean any form resulting from mechanical
- transformation or translation of a Source form, including but
- not limited to compiled object code, generated documentation,
- and conversions to other media types.
-
- "Work" shall mean the work of authorship, whether in Source or
- Object form, made available under the License, as indicated by a
- copyright notice that is included in or attached to the work
- (an example is provided in the Appendix below).
-
- "Derivative Works" shall mean any work, whether in Source or Object
- form, that is based on (or derived from) the Work and for which the
- editorial revisions, annotations, elaborations, or other modifications
- represent, as a whole, an original work of authorship. For the purposes
- of this License, Derivative Works shall not include works that remain
- separable from, or merely link (or bind by name) to the interfaces of,
- the Work and Derivative Works thereof.
-
- "Contribution" shall mean any work of authorship, including
- the original version of the Work and any modifications or additions
- to that Work or Derivative Works thereof, that is intentionally
- submitted to Licensor for inclusion in the Work by the copyright owner
- or by an individual or Legal Entity authorized to submit on behalf of
- the copyright owner. For the purposes of this definition, "submitted"
- means any form of electronic, verbal, or written communication sent
- to the Licensor or its representatives, including but not limited to
- communication on electronic mailing lists, source code control systems,
- and issue tracking systems that are managed by, or on behalf of, the
- Licensor for the purpose of discussing and improving the Work, but
- excluding communication that is conspicuously marked or otherwise
- designated in writing by the copyright owner as "Not a Contribution."
-
- "Contributor" shall mean Licensor and any individual or Legal Entity
- on behalf of whom a Contribution has been received by Licensor and
- subsequently incorporated within the Work.
-
- 2. Grant of Copyright License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- copyright license to reproduce, prepare Derivative Works of,
- publicly display, publicly perform, sublicense, and distribute the
- Work and such Derivative Works in Source or Object form.
-
- 3. Grant of Patent License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- (except as stated in this section) patent license to make, have made,
- use, offer to sell, sell, import, and otherwise transfer the Work,
- where such license applies only to those patent claims licensable
- by such Contributor that are necessarily infringed by their
- Contribution(s) alone or by combination of their Contribution(s)
- with the Work to which such Contribution(s) was submitted. If You
- institute patent litigation against any entity (including a
- cross-claim or counterclaim in a lawsuit) alleging that the Work
- or a Contribution incorporated within the Work constitutes direct
- or contributory patent infringement, then any patent licenses
- granted to You under this License for that Work shall terminate
- as of the date such litigation is filed.
-
- 4. Redistribution. You may reproduce and distribute copies of the
- Work or Derivative Works thereof in any medium, with or without
- modifications, and in Source or Object form, provided that You
- meet the following conditions:
-
- (a) You must give any other recipients of the Work or
- Derivative Works a copy of this License; and
-
- (b) You must cause any modified files to carry prominent notices
- stating that You changed the files; and
-
- (c) You must retain, in the Source form of any Derivative Works
- that You distribute, all copyright, patent, trademark, and
- attribution notices from the Source form of the Work,
- excluding those notices that do not pertain to any part of
- the Derivative Works; and
-
- (d) If the Work includes a "NOTICE" text file as part of its
- distribution, then any Derivative Works that You distribute must
- include a readable copy of the attribution notices contained
- within such NOTICE file, excluding those notices that do not
- pertain to any part of the Derivative Works, in at least one
- of the following places: within a NOTICE text file distributed
- as part of the Derivative Works; within the Source form or
- documentation, if provided along with the Derivative Works; or,
- within a display generated by the Derivative Works, if and
- wherever such third-party notices normally appear. The contents
- of the NOTICE file are for informational purposes only and
- do not modify the License. You may add Your own attribution
- notices within Derivative Works that You distribute, alongside
- or as an addendum to the NOTICE text from the Work, provided
- that such additional attribution notices cannot be construed
- as modifying the License.
-
- You may add Your own copyright statement to Your modifications and
- may provide additional or different license terms and conditions
- for use, reproduction, or distribution of Your modifications, or
- for any such Derivative Works as a whole, provided Your use,
- reproduction, and distribution of the Work otherwise complies with
- the conditions stated in this License.
-
- 5. Submission of Contributions. Unless You explicitly state otherwise,
- any Contribution intentionally submitted for inclusion in the Work
- by You to the Licensor shall be under the terms and conditions of
- this License, without any additional terms or conditions.
- Notwithstanding the above, nothing herein shall supersede or modify
- the terms of any separate license agreement you may have executed
- with Licensor regarding such Contributions.
-
- 6. Trademarks. This License does not grant permission to use the trade
- names, trademarks, service marks, or product names of the Licensor,
- except as required for reasonable and customary use in describing the
- origin of the Work and reproducing the content of the NOTICE file.
-
- 7. Disclaimer of Warranty. Unless required by applicable law or
- agreed to in writing, Licensor provides the Work (and each
- Contributor provides its Contributions) on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
- implied, including, without limitation, any warranties or conditions
- of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
- PARTICULAR PURPOSE. You are solely responsible for determining the
- appropriateness of using or redistributing the Work and assume any
- risks associated with Your exercise of permissions under this License.
-
- 8. Limitation of Liability. In no event and under no legal theory,
- whether in tort (including negligence), contract, or otherwise,
- unless required by applicable law (such as deliberate and grossly
- negligent acts) or agreed to in writing, shall any Contributor be
- liable to You for damages, including any direct, indirect, special,
- incidental, or consequential damages of any character arising as a
- result of this License or out of the use or inability to use the
- Work (including but not limited to damages for loss of goodwill,
- work stoppage, computer failure or malfunction, or any and all
- other commercial damages or losses), even if such Contributor
- has been advised of the possibility of such damages.
-
- 9. Accepting Warranty or Additional Liability. While redistributing
- the Work or Derivative Works thereof, You may choose to offer,
- and charge a fee for, acceptance of support, warranty, indemnity,
- or other liability obligations and/or rights consistent with this
- License. However, in accepting such obligations, You may act only
- on Your own behalf and on Your sole responsibility, not on behalf
- of any other Contributor, and only if You agree to indemnify,
- defend, and hold each Contributor harmless for any liability
- incurred by, or claims asserted against, such Contributor by reason
- of your accepting any such warranty or additional liability.
-
- END OF TERMS AND CONDITIONS
-
- APPENDIX: How to apply the Apache License to your work.
-
- To apply the Apache License to your work, attach the following
- boilerplate notice, with the fields enclosed by brackets "[]"
- replaced with your own identifying information. (Don't include
- the brackets!) The text should be enclosed in the appropriate
- comment syntax for the file format. We also recommend that a
- file or class name and description of purpose be included on the
- same "printed page" as the copyright notice for easier
- identification within third-party archives.
-
- Copyright [yyyy] [name of copyright owner]
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
+Copyright (c) 2016 The Inter Project Authors (https://github.com/rsms/inter)
+
+This Font Software is licensed under the SIL Open Font License, Version 1.1.
+This license is copied below, and is also available with a FAQ at:
+http://scripts.sil.org/OFL
+
+-----------------------------------------------------------
+SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
+-----------------------------------------------------------
+
+PREAMBLE
+The goals of the Open Font License (OFL) are to stimulate worldwide
+development of collaborative font projects, to support the font creation
+efforts of academic and linguistic communities, and to provide a free and
+open framework in which fonts may be shared and improved in partnership
+with others.
+
+The OFL allows the licensed fonts to be used, studied, modified and
+redistributed freely as long as they are not sold by themselves. The
+fonts, including any derivative works, can be bundled, embedded,
+redistributed and/or sold with any software provided that any reserved
+names are not used by derivative works. The fonts and derivatives,
+however, cannot be released under any other type of license. The
+requirement for fonts to remain under this license does not apply
+to any document created using the fonts or their derivatives.
+
+DEFINITIONS
+"Font Software" refers to the set of files released by the Copyright
+Holder(s) under this license and clearly marked as such. This may
+include source files, build scripts and documentation.
+
+"Reserved Font Name" refers to any names specified as such after the
+copyright statement(s).
+
+"Original Version" refers to the collection of Font Software components as
+distributed by the Copyright Holder(s).
+
+"Modified Version" refers to any derivative made by adding to, deleting,
+or substituting -- in part or in whole -- any of the components of the
+Original Version, by changing formats or by porting the Font Software to a
+new environment.
+
+"Author" refers to any designer, engineer, programmer, technical
+writer or other person who contributed to the Font Software.
+
+PERMISSION AND CONDITIONS
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of the Font Software, to use, study, copy, merge, embed, modify,
+redistribute, and sell modified and unmodified copies of the Font
+Software, subject to the following conditions:
+
+1) Neither the Font Software nor any of its individual components,
+in Original or Modified Versions, may be sold by itself.
+
+2) Original or Modified Versions of the Font Software may be bundled,
+redistributed and/or sold with any software, provided that each copy
+contains the above copyright notice and this license. These can be
+included either as stand-alone text files, human-readable headers or
+in the appropriate machine-readable metadata fields within text or
+binary files as long as those fields can be easily viewed by the user.
+
+3) No Modified Version of the Font Software may use the Reserved Font
+Name(s) unless explicit written permission is granted by the corresponding
+Copyright Holder. This restriction only applies to the primary font name as
+presented to the users.
+
+4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
+Software shall not be used to promote, endorse or advertise any
+Modified Version, except to acknowledge the contribution(s) of the
+Copyright Holder(s) and the Author(s) or with their explicit written
+permission.
+
+5) The Font Software, modified or unmodified, in part or in whole,
+must be distributed entirely under this license, and must not be
+distributed under any other license. The requirement for fonts to
+remain under this license does not apply to any document created
+using the Font Software.
+
+TERMINATION
+This license becomes null and void if any of the above conditions are
+not met.
+
+DISCLAIMER
+THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
+OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
+COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
+DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
+OTHER DEALINGS IN THE FONT SOFTWARE.
diff --git a/fonts/inter-latin-ext.woff2 b/fonts/inter-latin-ext.woff2
new file mode 100644
index 0000000..479d010
Binary files /dev/null and b/fonts/inter-latin-ext.woff2 differ
diff --git a/fonts/inter-latin.woff2 b/fonts/inter-latin.woff2
new file mode 100644
index 0000000..d15208d
Binary files /dev/null and b/fonts/inter-latin.woff2 differ
diff --git a/fonts/roboto-slab-latin-ext.woff2 b/fonts/roboto-slab-latin-ext.woff2
deleted file mode 100644
index e3a3e09..0000000
Binary files a/fonts/roboto-slab-latin-ext.woff2 and /dev/null differ
diff --git a/fonts/roboto-slab-latin.woff2 b/fonts/roboto-slab-latin.woff2
deleted file mode 100644
index 9c7f6ae..0000000
Binary files a/fonts/roboto-slab-latin.woff2 and /dev/null differ
diff --git a/images/logo_text_half.avif b/images/logo_text_half.avif
deleted file mode 100644
index d46e37f..0000000
Binary files a/images/logo_text_half.avif and /dev/null differ
diff --git a/images/logo_text_half.png b/images/logo_text_half.png
deleted file mode 100644
index bc28a87..0000000
Binary files a/images/logo_text_half.png and /dev/null differ
diff --git a/images/logo_text_half.webp b/images/logo_text_half.webp
deleted file mode 100644
index 0412cf8..0000000
Binary files a/images/logo_text_half.webp and /dev/null differ
diff --git a/index-with-flexslider.html b/index-with-flexslider.html
index 4f1c646..ee4d4af 100644
--- a/index-with-flexslider.html
+++ b/index-with-flexslider.html
@@ -36,12 +36,10 @@
-
+
@@ -79,10 +77,7 @@
-
- 01.
- About
-
+ About
-
- 02.
- Works
-
+ Works
-
- 03.
- Shop
-
+ Shop
-
- 04.
- Blog
-
+ Blog
@@ -136,14 +122,13 @@
diff --git a/index-with-iosslider.html b/index-with-iosslider.html
index 3621ea7..9386659 100644
--- a/index-with-iosslider.html
+++ b/index-with-iosslider.html
@@ -36,12 +36,10 @@
-
+
@@ -79,10 +77,7 @@
-
- 01.
- About
-
+ About
-
- 02.
- Works
-
+ Works
-
- 03.
- Shop
-
+ Shop
-
- 04.
- Blog
-
+ Blog
@@ -136,14 +122,13 @@
diff --git a/index.html b/index.html
index 4e76484..46c3cb8 100644
--- a/index.html
+++ b/index.html
@@ -35,6 +35,12 @@
+
+
+
@@ -71,10 +77,7 @@
-
- 01.
- About
-
+ About
-
- 02.
- Works
-
+ Works
-
- 03.
- Shop
-
+ Shop
-
- 04.
- Blog
-
+ Blog
@@ -128,14 +122,13 @@
diff --git a/js/typefolio.js b/js/typefolio.js
index a351e84..2e1802c 100644
--- a/js/typefolio.js
+++ b/js/typefolio.js
@@ -31,41 +31,16 @@
mobileMenuId: 'menu-mobile',
toggleElementId: 'toggle-menu',
menuOnCollapseText: 'Menu',
- menuOnExpandText: 'Close',
- addFirstLevelArrow: true,
- firstLevelArrow: '▾',
- addDeeperLevelArrow: true,
- deeperLevelArrow: '▸'
+ menuOnExpandText: 'Close'
};
function initMenu(nav, options) {
var opts = Object.assign({}, MENU_DEFAULTS, options || {});
- // Snapshot the markup before the arrows go in, so the phone menu
- // does not inherit decorations meant for the desktop bar.
- var sourceMarkup = nav.innerHTML;
-
- if (opts.addFirstLevelArrow) {
- addArrows(nav.querySelectorAll(':scope > li:has(> ul) > a'), opts.firstLevelArrow);
- }
-
- if (opts.addDeeperLevelArrow) {
- addArrows(nav.querySelectorAll(':scope li ul li:has(> ul) > a'), opts.deeperLevelArrow);
- }
-
- buildMobileMenu(nav, sourceMarkup, opts);
- }
-
- function addArrows(links, glyph) {
- Array.prototype.forEach.call(links, function (link) {
- var span = document.createElement('span');
- span.className = 'arrow';
- span.textContent = ' ' + glyph;
-
- // Decorative: the link text already says where it goes.
- span.setAttribute('aria-hidden', 'true');
- link.appendChild(span);
- });
+ // The chevron on a parent item is drawn by CSS, so the markup the
+ // phone menu is cloned from carries no desktop decoration and there
+ // is nothing to snapshot around.
+ buildMobileMenu(nav, nav.innerHTML, opts);
}
function buildMobileMenu(nav, sourceMarkup, opts) {
@@ -258,6 +233,85 @@
}
});
+ /*
+ Drag to navigate.
+
+ A touch screen and a trackpad can already pan the track; a mouse
+ has nothing to grab, so pan it here. Snapping is switched off for
+ the length of the drag - mandatory snapping fights every pixel of
+ a scrollLeft written by hand - and the nearest slide is snapped
+ to on release.
+ */
+ var drag = null;
+ var dragged = false;
+
+ track.classList.add('is-draggable');
+
+ /*
+ Without this the browser starts dragging the artwork itself the
+ moment the pointer moves, and the gesture is over: a native image
+ drag swallows every pointer event that would have followed.
+ */
+ track.addEventListener('dragstart', function (event) {
+ event.preventDefault();
+ });
+
+ track.addEventListener('pointerdown', function (event) {
+ // Leave touch and pen to the browser, which does this better.
+ if (event.pointerType !== 'mouse' || event.button !== 0) return;
+
+ drag = {
+ id: event.pointerId,
+ startX: event.clientX,
+ startLeft: track.scrollLeft,
+ moved: false
+ };
+ });
+
+ track.addEventListener('pointermove', function (event) {
+ if (!drag || event.pointerId !== drag.id) return;
+
+ var dx = event.clientX - drag.startX;
+
+ // Under a few pixels this is someone clicking a slide, not
+ // dragging it.
+ if (!drag.moved) {
+ if (Math.abs(dx) < 4) return;
+
+ drag.moved = true;
+ track.classList.add('is-dragging');
+ track.setPointerCapture(drag.id);
+ }
+
+ track.scrollLeft = drag.startLeft - dx;
+ event.preventDefault();
+ });
+
+ function endDrag(event) {
+ if (!drag || (event && event.pointerId !== drag.id)) return;
+
+ var moved = drag.moved;
+ if (track.hasPointerCapture(drag.id)) track.releasePointerCapture(drag.id);
+ drag = null;
+ dragged = moved;
+ track.classList.remove('is-dragging');
+
+ // Snapping was off for the drag, so land on a slide.
+ if (moved) goTo(nearestSlide());
+ }
+
+ track.addEventListener('pointerup', endDrag);
+ track.addEventListener('pointercancel', endDrag);
+
+ // A drag that happens to end on a link must not follow it.
+ track.addEventListener('click', function (event) {
+ if (!dragged) return;
+
+ dragged = false;
+ event.preventDefault();
+ event.stopPropagation();
+ }, true);
+
var scrollTimer;
track.addEventListener('scroll', function () {
clearTimeout(scrollTimer);
diff --git a/shop-item.html b/shop-item.html
index 8f43a75..1796e3c 100644
--- a/shop-item.html
+++ b/shop-item.html
@@ -35,6 +35,12 @@
+
+
+
@@ -71,10 +77,7 @@
-
- 01.
- About
-
+ About
-
- 02.
- Works
-
+ Works
-
- 03.
- Shop
-
+ Shop
-
- 04.
- Blog
-
+ Blog
@@ -128,14 +122,13 @@
diff --git a/shop.html b/shop.html
index eb44f04..527f011 100644
--- a/shop.html
+++ b/shop.html
@@ -35,6 +35,12 @@
+
+
+
@@ -71,10 +77,7 @@
-
- 01.
- About
-
+ About
-
- 02.
- Works
-
+ Works
-
- 03.
- Shop
-
+ Shop
-
- 04.
- Blog
-
+ Blog
@@ -128,14 +122,13 @@
@@ -164,13 +157,13 @@
Shop
-
-
-
-
@@ -276,7 +269,7 @@
Synth Black Label
-
-
-
@@ -385,7 +378,7 @@
Small Ben
-
-
-
@@ -491,7 +484,7 @@
Kudos Silverware
-
-
-
@@ -600,7 +593,7 @@
Scandinavian Series VI
-
+
@@ -618,8 +611,8 @@
Scandinavian Series VI
-
-
+
+
diff --git a/single-architecture-sidebar-right.html b/single-architecture-sidebar-right.html
index b1e65df..e26c2be 100644
--- a/single-architecture-sidebar-right.html
+++ b/single-architecture-sidebar-right.html
@@ -35,6 +35,12 @@
+
+
+
@@ -71,10 +77,7 @@