Commits: 6

Prevent multiple h1 headings

This is not a good practice as described here:

https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/Heading_Elements#avoid_using_multiple_h1_elements_on_one_page

The problem is that headings come from markdown documents. Authors of content shouldn't be bothered with the structure of page around their content - it's a responsibility of templates.

Now content should always use headings starting from h1 (markdown #) and templates can set the base level using the new demote_headings component.

index 37f6807..bb9e6d0 100644
--- a/templates/components.html
+++ b/templates/components.html
@@ -194,3 +194,20 @@
=    {\% endif %}
=  {\% endfor %}
={\% endmacro title %}
+
+{\% macro demote_headings (content, levels=1) %}
+  {\% set_global demoted = content %}
+  {\% for i in range(start=1, end=6) %}
+  {\% set n = 6 - i %}
+  {\% set m = n + 1 %}
+  {\% set from_opening = "<h" ~ n %}
+  {\% set into_opening = "<h" ~ m %}
+  {\% set from_closing = "</h" ~ n %}
+  {\% set into_closing = "</h" ~ m %}
+  {\% set_global demoted = demoted
+     | replace (from=from_opening, to=into_opening)
+     | replace (from=from_closing, to=into_closing)
+  %}
+  {\% endfor %}
+  {\{ demoted | safe \}}
+{\% endmacro table_of_contents %}
index 4a9795b..374bb55 100644
--- a/templates/index.html
+++ b/templates/index.html
@@ -1,5 +1,7 @@
={\% extends "base.html" %}
=
={\%- block main_content -%}
-{\{- section.content | safe -\}}
+{\{- components::demote_headings (content=section.content)
+    | safe
+-\}}
={\%- endblock main_content -%}
index 61d3aed..de828d3 100644
--- a/templates/section.html
+++ b/templates/section.html
@@ -2,6 +2,10 @@
=
={\% extends "base.html" %}
=
+{\% import "components.html" as components %}
+
={\%- block main_content -%}
-{\{- section.content | safe -\}}
+{\{- components::demote_headings (content=section.content)
+    | safe
+-\}}
={\%- endblock main_content -%}

Landing: add the call to action to first paragraph

Also integrate the link at the bottom with the text.

index 3efaddd..c5e3ffd 100644
--- a/content/_index.md
+++ b/content/_index.md
@@ -1,7 +1,7 @@
=---
=---
=
-Move away from big tech. Stay in control of your tools, your data, and your values.
+Move away from big tech. Stay in control of your tools, your data, and your values. [Book a call to learn more](https://cal.com/tad-lispy/esc-co-intro)
=
={\{ table_of_contents() \}}
=
@@ -69,6 +69,5 @@ We're built for organisations with long-term goals, and who care about autonomy,
=
=You're not stuck. There are better tools. And you don't need to figure them out alone.
=
-Book a free 30-minute intro call to see what switching away from big tech could look like for you.
+[Book a free 30-minute intro call](https://cal.com/tad-lispy/esc-co-intro) to see what switching away from big tech could look like for you.
=
-[Book a Call](https://cal.com/tad-lispy/esc-co-intro)

Use a call-me moji on home page

Improve and simplify moji sizing. Make moji lists bullets bigger.

index c5e3ffd..52bfa0d 100644
--- a/content/_index.md
+++ b/content/_index.md
@@ -1,7 +1,7 @@
=---
=---
=
-Move away from big tech. Stay in control of your tools, your data, and your values. [Book a call to learn more](https://cal.com/tad-lispy/esc-co-intro)
+Move away from big tech. Stay in control of your tools, your data, and your values. [Book a call to learn more](https://cal.com/tad-lispy/esc-co-intro) {\{ om (moji="call me hand") \}}
=
={\{ table_of_contents() \}}
=
index 72b4de3..10e0501 100644
--- a/static/openmoji-preamble.css
+++ b/static/openmoji-preamble.css
@@ -7,17 +7,18 @@ Preamble from https://ellekasai.github.io/twemoji-awesome/,
=licensed under MIT: https://ellekasai.mit-license.org/
=*/
=
+:root {
+    --moji-base-size: 1lh;
+}
+
=.om {
-    --om-path: calc("./openmoji-svg-color/" + var(--om-hexcode) + ".svg");
-    background-image: url("./openmoji-svg-color/"var(--om-hexcode)".svg");
=    display: inline-block;
-    height: 1em;
-    width: 1em;
-    margin: 0 .05em 0 .1em;
-    vertical-align: -0.1em;
+    height: var(--moji-base-size);
+    width: var(--moji-base-size);
+    vertical-align: middle;
=    background-repeat: no-repeat;
=    background-position: center center;
-    background-size: 1em 1em;
+    background-size: contain;
=}
=
=/* When applied to a list item, use it as a bullet */
@@ -26,57 +27,45 @@ li.om {
=    list-style: none;
=    width: unset;
=    margin-left: -1.1em;
-    padding-left: 1.1em;
+    padding-left: 2lh;
=    height: initial;
-    background-size: 0.9em;
-    background-position-y: 0.1em;
=    background-position-x: 0.0em;
+    margin-top: 0.5em;
+    line-height: 1.5em;
=}
=
=.om-lg {
-    height: 1.33em;
-    width: 1.33em;
+    height: 1.33lh;
+    width: 1.33lh;
=    margin: 0 0.0665em 0 0.133em;
-    vertical-align: -0.15em;
-    background-size: 1.33em 1.33em;
=}
=
=.om-bg {
-    height: 1.5em;
-    width: 1.5em;
+    height: calc(1.5 * var(--moji-base-size));
+    width: calc(1.5 * var(--moji-base-size));
=    margin: 0 0.075em 0 0.15em;
-    vertical-align: -0.2em;
-    background-size: 1.5em 1.5em;
=}
=
=.om-2x {
-    height: 2em;
-    width: 2em;
+    height: calc(2 * var(--moji-base-size));
+    width: calc(2 * var(--moji-base-size));
=    margin: 0 0.1em 0 0.2em;
-    vertical-align: -0.7em;
-    background-size: 2em 2em;
=}
=
=.om-3x {
-    height: 3em;
-    width: 3em;
+    height: calc(3 * var(--moji-base-size));
+    width: calc(3 * var(--moji-base-size));
=    margin: 0 0.15em 0 0.3em;
-    vertical-align: -1.1em;
-    background-size: 3em 3em;
=}
=
=.om-4x {
-    height: 4em;
-    width: 4em;
+    height: calc(4 * var(--moji-base-size));
+    width: calc(4 * var(--moji-base-size));
=    margin: 0 0.2em 0 0.4em;
-    vertical-align: -1.5em;
-    background-size: 4em 4em;
=}
=
=.om-5x {
-    height: 5em;
-    width: 5em;
+    height: calc(5 * var(--moji-base-size));
+    width: calc(5 * var(--moji-base-size));
=    margin: 0 0.25em 0 0.5em;
-    vertical-align: -1.6em;
-    background-size: 5em 5em;
=}
new file mode 100644
index 0000000..bd99dfb
--- /dev/null
+++ b/templates/shortcodes/om.html
@@ -0,0 +1,7 @@
+{\% import "components.html" as components %}
+
+{\% if not size %}
+{\% set size="1x" %}
+{\% endif %}
+
+{\{ components::openmoji (moji=moji, size=size) \}}

Moar moji on landing

index 52bfa0d..e214cef 100644
--- a/content/_index.md
+++ b/content/_index.md
@@ -5,7 +5,8 @@ Move away from big tech. Stay in control of your tools, your data, and your valu
=
={\{ table_of_contents() \}}
=
-# Why make the switch?
+
+# {\{ om(moji="trump" size="2x") \}} Why make the switch?
=
=Most organisations rely on Google or Microsoft tools because they feel like the default.
=
@@ -18,7 +19,8 @@ But that choice comes with trade-offs:
=
=For many mission-led teams, that's no longer acceptable.
=
-# What we do
+
+# {\{ om(moji="handshake" size="2x") \}} What we do
=
=ESC Collective helps you move to European and open source alternatives without the complexity.
=
@@ -31,6 +33,7 @@ We guide you through the transition from proprietary platforms to ethical tools
=
=[You can read more about our services here](@/services/_index.md).
=
+
=# How it works
=
=We don't drop a list of tools and walk away. We work with you from start to finish.
@@ -51,7 +54,8 @@ We don't drop a list of tools and walk away. We work with you from start to fini
=
=    We train your team in plain language and stay available for any follow-up questions or support.
=
-# Who we work with
+
+# {\{ om(moji="index pointing at the viewer" size="2x") \}} Who we work with
=
=We're built for organisations with long-term goals, and who care about autonomy, privacy, and sustainability:
=
@@ -60,7 +64,8 @@ We're built for organisations with long-term goals, and who care about autonomy,
=- Schools and Educational Projects
=- Local governments and public sector organisations
=
-# Why ESC Collective?
+
+# {\{ om(moji="glowing star" size="2x") \}} Why Esc Collective?
=
=* We're a cooperative, not a corporation
=* We rely on cloud infrastructure in countries with strict privacy regulations

Make "How we work" list display as numbered cards

index e214cef..2586bef 100644
--- a/content/_index.md
+++ b/content/_index.md
@@ -38,6 +38,7 @@ We guide you through the transition from proprietary platforms to ethical tools
=
=We don't drop a list of tools and walk away. We work with you from start to finish.
=
+{\% wrap_with(tag="div", class="full-bleed card-list card-rows-4") %}
=1. Understand
=
=    We start with a simple conversation about what you use now, what's not working, and what you'd like instead.
@@ -53,6 +54,7 @@ We don't drop a list of tools and walk away. We work with you from start to fini
=4. Support
=
=    We train your team in plain language and stay available for any follow-up questions or support.
+{\% end %}
=
=
=# {\{ om(moji="index pointing at the viewer" size="2x") \}} Who we work with
index 56e41c5..d08cf82 100644
--- a/templates/base.html
+++ b/templates/base.html
@@ -163,6 +163,8 @@
=        flex-wrap: wrap;
=        gap: 2rem;
=        list-style: none;
+        padding: 0;
+        margin-bottom: 4em;
=
=        li {
=          --inactive-color: oklch(from var(--accent-color) 60% C H);
@@ -254,7 +256,7 @@
=        font-size: 150%;
=      }
=
-      .card-grid {
+      .card-grid, .card-list > ol {
=        display: grid;
=        grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
=        grid-auto-rows: 1fr;
@@ -269,9 +271,30 @@
=          }
=        }
=
+        counter-reset: card-index 0;
+
+        > li {
+          display: flex;
+          flex-direction: column;
+          counter-increment: card-index;
+
+          &::before {
+            content: counter(card-index);
+            display: flex;
+            justify-content: center;
+            background: var(--yellow);
+            width: 2em;
+            height: 2em;
+            align-items: center;
+            margin: 0 auto;
+            border-radius: 50%;
+            font-weight: bold;
+            color: var(--dark-color);
+          }
+        }
=      }
=
-      article {
+      article, .card-list > ol > li {
=        background-color: white;
=        border-radius: 8px;
=        box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
@@ -290,6 +313,34 @@
=        }
=      }
=
+      .card-list {
+        display: flex;
+        justify-content: center;
+
+        > ol {
+          padding: 0;
+          grid-template-columns: repeat(auto-fill, minmax(12ch, 1fr));
+          max-width: 100ch;
+        }
+
+        &.card-rows-4 > ol {
+          grid-template-columns: repeat(1, 1fr);
+
+          @media (min-width: 48ch) {
+            grid-template-columns: repeat(2, 1fr);
+          }
+
+          @media (min-width: 100ch) {
+            grid-template-columns: repeat(4, 1fr);
+          }
+
+          > li > p:first-child {
+            font-weight: bold;
+            text-align: center;
+          }
+        }
+      }
+
=      a:has(> article) {
=        display: block;
=        text-decoration: none;
@@ -310,6 +361,12 @@
=
=      /* UTILITY CLASSES */
=
+      .full-bleed {
+        --negative-margin: calc(-1 * var(--full-bleed-margin));
+        margin-left: var(--negative-margin);
+        margin-right: var(--negative-margin);
+      }
+
=      .full-bleed-background {
=        --negative-margin: calc(-1 * var(--full-bleed-margin));
=        margin-left: var(--negative-margin);
@@ -317,6 +374,7 @@
=        padding: 3rem calc(1rem + var(--full-bleed-margin));
=      }
=
+
=      /* PROMPT ANIMATION */
=
=      .prompt {
new file mode 100644
index 0000000..f1684d7
--- /dev/null
+++ b/templates/shortcodes/wrap_with.html
@@ -0,0 +1,3 @@
+<{\{ tag \}} class="{\{ class \}}">
+{\{ body | markdown | safe \}}
+</{\{tag\}}>

Do not use big font on home page when mobile

The fonts on narrow screens look too big.

index d08cf82..03ca26e 100644
--- a/templates/base.html
+++ b/templates/base.html
@@ -81,7 +81,10 @@
=      .home {
=
=        main {
-          font-size: 150%;
+          @media (min-width: 36rem) {
+            font-size: 150%;
+          }
+
=        }
=
=        main h2 {