Cannabis Freedom Index

Changelog 974ea0e

better look

4 files of code, design or docs +231 −136 lines

Code, design and documents 4 files

src/components/Changes.astro +20 −26
@@ -1,8 +1,7 @@
 ---
-// Home page: the four most recent changes as a small vertical timeline (date on the left,
-// details on the right), next to the world average chart. See /changes.yaml.
+// Home page: the four most recent changes as a ledger, one row each: date, country, what
+// happened, and the score before and after. See /changes.yaml.
 import { changes } from "../lib/countries.js";
 import { tierColor } from "../lib/tiers.js";
-import AverageChart from "./AverageChart.astro";
 import ScoreChange from "./ScoreChange.astro";
 
@@ -12,25 +11,20 @@ const shortDate = (iso) =>
   iso.length === 4 ? iso : new Date(`${iso.length === 7 ? iso + "-01" : iso}T00:00:00Z`).toLocaleDateString("en-GB", { day: iso.length === 7 ? undefined : "numeric", month: "short", year: "numeric", timeZone: "UTC" });
 ---
-<div class="home-split">
-  <section class="card changes" aria-labelledby="changesTitle">
-    <div class="changes-head">
-      <h2 class="changes-title" id="changesTitle">Latest changes</h2>
-      <a href={`${base}history/`}>Full history →</a>
-    </div>
-    <ol class="mini-tl">
-      {changes.filter((ch) => ch.score).slice(0, 4).map((ch) => (
-        <li style={`--c:${tierColor(ch.score.after)}`}>
-          <a href={`${base}history/${ch.id}/`}>
-            <time datetime={ch.date}>{shortDate(ch.date)}</time>
-            <span class="mini-tl-body">
-              <span class="mini-tl-country">{ch.country.flag} {ch.country.name}</span>
-              <b><span class="kind" title={ch.kind.label} aria-hidden="true">{ch.kind.emoji}</span><span class="visually-hidden">{ch.kind.label}: </span>{ch.title}</b>
-              <ScoreChange score={ch.score} />
-            </span>
-          </a>
-        </li>
-      ))}
-    </ol>
-  </section>
-  <AverageChart />
-</div>
+<section class="ledger" aria-labelledby="changesTitle">
+  <div class="ledger-head">
+    <h2 id="changesTitle">Latest changes</h2>
+    <a href={`${base}history/`}>Full history →</a>
+  </div>
+  <ol>
+    {changes.filter((ch) => ch.score).slice(0, 4).map((ch) => (
+      <li style={`--c:${tierColor(ch.score.after)}`}>
+        <a href={`${base}history/${ch.id}/`}>
+          <time datetime={ch.date}>{shortDate(ch.date)}</time>
+          <span class="ledger-place">{ch.country.flag} {ch.country.name}</span>
+          <b><span class="visually-hidden">{ch.kind.label}: </span>{ch.title}</b>
+          <ScoreChange score={ch.score} />
+        </a>
+      </li>
+    ))}
+  </ol>
+</section>

src/layouts/Base.astro +1 −1
@@ -38,5 +38,5 @@ const schemas = jsonld ? [jsonld].flat() : [];
   <link rel="preconnect" href="https://fonts.googleapis.com">
   <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
-  <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&family=Space+Grotesk:wght@500;600;700&display=swap" rel="stylesheet">
+  <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&family=Instrument+Serif:ital@0;1&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet">
   <script is:inline>
     // Set the theme before first paint to avoid a flash.

src/pages/index.astro +13 −6
@@ -3,4 +3,5 @@ import Base from "../layouts/Base.astro";
 import DidYouKnow from "../components/DidYouKnow.astro";
 import Changes from "../components/Changes.astro";
+import AverageChart from "../components/AverageChart.astro";
 import { SEGMENTS, DATA_SNAPSHOT, REC_LABEL, REC_ORDER, REC_HELP, MED_LABEL, MED_HELP, countries, regions, worldAvg, lastUpdated, formatDate, subunitsOf, places, trendOf, changeDate, TREND_YEARS } from "../lib/countries.js";
 import { TIERS, tierColor } from "../lib/tiers.js";
@@ -105,10 +106,16 @@ const columnGroups = [["Shown by default", BASE_COLUMNS], ...["Score segments",
 <Base description={`Where is cannabis legal? Cannabis laws in ${countries.length} countries, each scored from 0 to 100 for possession, home growing, penalties and legal access, with a world map, rankings${SHOW_PRICES ? ", retail prices" : ""} and legal history.`} jsonld={homeSeo(Astro.site, countries.length)}>
   <main id="top">
-    <section class="hero">
-      <p class="eyebrow">Global index · {DATA_SNAPSHOT} edition</p>
-      <h1>How free is cannabis<br>in every country?</h1>
-      <p class="lede">Every country gets a score from 0 to 100. It shows how free you are to carry, grow, share and use cannabis. See the map, rankings{SHOW_PRICES && ", sourced retail prices"} and how each country's laws changed over time.</p>
-      <div class="stats">
-        {stats.map(([n, label, tone]) => <div class={`stat ${tone ?? ""}`}><div class="big">{n}</div><div class="label">{label}</div></div>)}
+    {/* The opening: the question, the answer in one number with its history, then what just changed. */}
+    <section class="front">
+      <p class="eyebrow">Cannabis Freedom Index <span>{DATA_SNAPSHOT} edition</span></p>
+      <h1>How free is cannabis <em>in every country?</em></h1>
+      <div class="front-grid">
+        <div class="front-intro">
+          <p class="lede">Every country gets a score from 0 to 100 for how free you are to carry, grow, share and use cannabis. Below: the map, the rankings{SHOW_PRICES && ", sourced retail prices"} and how each country's law got where it is.</p>
+          <dl class="front-stats">
+            {stats.map(([n, label, tone]) => <div class={tone ?? ""}><dt>{n}</dt><dd>{label}</dd></div>)}
+          </dl>
+        </div>
+        <AverageChart />
       </div>
       <Changes />

src/styles/global.css +197 −103
@@ -1,13 +1,17 @@
 /* ── Tokens ─────────────────────────────────────────── */
 :root {
-  --bg: #0a0f0c;
-  --surface: #111814;
-  --surface-2: #18211c;
-  --border: #233029;
-  --text: #ecf3ee;
-  --text-2: #a9b8ae;
-  --muted: #74857a;
-  --accent: #5fd97f;
-  --accent-ink: #06210f;
+  /* Monochrome: ink on near-black. The red-to-green freedom scale is the only colour on the site. */
+  --bg: #0c0c0b;
+  --surface: #121211;
+  --surface-2: #1a1a18;
+  --border: #2a2a27;
+  --text: #f2f0e9;
+  --text-2: #a9a79d;
+  --muted: #77756c;
+  --accent: #f2f0e9;
+  --accent-ink: #0c0c0b;
+  --display: "Instrument Serif", "Iowan Old Style", Georgia, serif; /* headlines */
+  --mono: "JetBrains Mono", ui-monospace, "SF Mono", Menlo, monospace; /* labels and figures */
+  --r: 2px; /* the one corner radius */
   /* red → green freedom scale, shared by both themes */
   --t0: #a3121f;
@@ -17,7 +21,7 @@
   --t4: #9ccc55;
   --t5: #2e9e4f;
-  --nodata: #1a1f1c;
-  --hatch: #2c3530;
-  --land: #2a322d; /* land that is not a country: Antarctica */
+  --nodata: #181817;
+  --hatch: #2e2e2b;
+  --land: #2a2a27; /* land that is not a country: Antarctica */
   /* cannabis use on the map: one hue, more is lighter on the dark theme */
   --u0: #1b2c45; --u1: #24456f; --u2: #2f65a3; --u3: #5591d3; --u4: #a3c8f2;
@@ -28,16 +32,16 @@
 }
 :root[data-theme="light"] {
-  --bg: #f5f7f4;
-  --surface: #ffffff;
-  --surface-2: #eef2ee;
-  --border: #dde4de;
-  --text: #0f1a13;
-  --text-2: #46554b;
-  --muted: #6d7c72;
-  --accent: #14803f;
-  --accent-ink: #ffffff;
-  --nodata: #f0f1f0;
-  --hatch: #d5dad6;
-  --land: #dfe3df;
+  --bg: #f4f2eb;
+  --surface: #fbfaf5;
+  --surface-2: #eae7dd;
+  --border: #d9d5c8;
+  --text: #11110f;
+  --text-2: #4b4a43;
+  --muted: #7a786d;
+  --accent: #11110f;
+  --accent-ink: #f4f2eb;
+  --nodata: #efede5;
+  --hatch: #d6d2c5;
+  --land: #e2dfd4;
   /* …and darker on the light theme */
   --u0: #dfe9f5; --u1: #b0cbea; --u2: #74a2d8; --u3: #3f77bd; --u4: #1c4a8f;
@@ -56,10 +60,10 @@ body {
   -webkit-font-smoothing: antialiased;
 }
-h1, h2, h3, .brand, .big { font-family: "Space Grotesk", Inter, system-ui, sans-serif; letter-spacing: -.02em; }
+h1, h2, h3, .brand, .big { font-family: var(--display); letter-spacing: -.02em; }
 h2 { font-size: 28px; margin: 0 0 4px; }
 h3 { font-size: 17px; margin: 0 0 8px; }
 p { margin: 0 0 12px; }
 a { color: inherit; text-decoration: none; }
-code { background: var(--surface-2); padding: 1px 6px; border-radius: 5px; font-size: 13px; }
+code { background: var(--surface-2); padding: 1px 6px; border-radius: var(--r); font-size: 13px; }
 .num, .big, td.num, .score-val { font-variant-numeric: tabular-nums; }
 
@@ -76,5 +80,5 @@ code { background: var(--surface-2); padding: 1px 6px; border-radius: 5px; font-
 .brand-mark {
   display: grid; place-items: center; width: 34px; height: 34px;
-  border-radius: 10px; background: var(--accent); color: var(--accent-ink);
+  border-radius: var(--r); background: var(--accent); color: var(--accent-ink);
 }
 .nav { display: flex; gap: clamp(12px, 2vw, 22px); margin-left: auto; }
@@ -85,5 +89,5 @@ code { background: var(--surface-2); padding: 1px 6px; border-radius: 5px; font-
 .icon-btn {
   display: grid; place-items: center; width: 34px; height: 34px;
-  border: 1px solid var(--border); border-radius: 10px;
+  border: 1px solid var(--border); border-radius: var(--r);
   background: var(--surface); color: var(--text-2);
   font-size: 17px; line-height: 1; cursor: pointer;
@@ -101,5 +105,5 @@ main { max-width: 1240px; margin: 0 auto; padding: 0 clamp(16px, 4vw, 40px); }
 .card {
   background: var(--surface); border: 1px solid var(--border);
-  border-radius: 18px;
+  border-radius: var(--r);
 }
 
@@ -112,11 +116,4 @@ main { max-width: 1240px; margin: 0 auto; padding: 0 clamp(16px, 4vw, 40px); }
 h1 { font-size: clamp(36px, 6.2vw, 68px); line-height: 1.02; margin: 0 0 18px; }
 .lede { font-size: clamp(16px, 1.6vw, 19px); color: var(--text-2); max-width: 62ch; }
-.stats {
-  display: grid; grid-template-columns: repeat(auto-fit, minmax(170px, 1fr));
-  gap: 12px; margin-top: 34px;
-}
-.stat { padding: 18px 20px; border-radius: 16px; background: var(--surface); border: 1px solid var(--border); }
-.stat .big { font-size: 34px; font-weight: 700; line-height: 1.1; }
-.stat .label { color: var(--text-2); font-size: 13.5px; }
 
 /* ── Form controls ──────────────────────────────────── */
@@ -126,5 +123,5 @@ select, input[type="search"] {
   font: inherit; color: var(--text);
   background: var(--surface); border: 1px solid var(--border);
-  border-radius: 10px; padding: 8px 12px; min-width: 0;
+  border-radius: var(--r); padding: 8px 12px; min-width: 0;
 }
 input[type="search"] { width: 200px; }
@@ -151,5 +148,5 @@ select:focus-visible, input:focus-visible, button:focus-visible, tr:focus-visibl
 .tooltip {
   position: absolute; pointer-events: none; z-index: 5;
-  min-width: 170px; padding: 10px 12px; border-radius: 12px;
+  min-width: 170px; padding: 10px 12px; border-radius: var(--r);
   background: var(--surface-2); border: 1px solid var(--border); box-shadow: var(--shadow);
   font-size: 13px;
@@ -166,5 +163,5 @@ select:focus-visible, input:focus-visible, button:focus-visible, tr:focus-visibl
 .legend[hidden] { display: none; }
 .legend .legend-note { flex-basis: 100%; color: var(--muted); }
-.sw { width: 14px; height: 14px; border-radius: 4px; border: 1px solid var(--border); flex: none; }
+.sw { width: 14px; height: 14px; border-radius: var(--r); border: 1px solid var(--border); flex: none; }
 .sw-nodata { background: repeating-linear-gradient(45deg, var(--nodata) 0 3px, var(--hatch) 3px 5px); }
 
@@ -202,11 +199,11 @@ th.num-col { text-align: right; }
 .approx { color: var(--muted); margin-right: 1px; }
 .score-val { width: 28px; text-align: right; font-weight: 600; }
-.bar { flex: 1; height: 8px; border-radius: 4px; background: var(--surface-2); position: relative; }
-.bar > i { position: absolute; inset: 0 auto 0 0; border-radius: 4px; min-width: 3px; }
+.bar { flex: 1; height: 8px; border-radius: var(--r); background: var(--surface-2); position: relative; }
+.bar > i { position: absolute; inset: 0 auto 0 0; border-radius: var(--r); min-width: 3px; }
 .empty { padding: 36px; text-align: center; color: var(--muted); }
 
 .chip {
   display: inline-flex; align-items: center; gap: 6px;
-  padding: 2px 10px; border-radius: 999px; font-size: 12.5px; font-weight: 500;
+  padding: 2px 10px; border-radius: var(--r); font-size: 12.5px; font-weight: 500;
   background: var(--surface-2); color: var(--text-2); border: 1px solid var(--border);
   white-space: nowrap;
@@ -228,10 +225,10 @@ th.num-col { text-align: right; }
   display: grid; place-items: center; overflow: hidden;
 }
-.weights div:first-child { border-radius: 8px 0 0 8px; }
+.weights div:first-child { border-radius: var(--r); }
 .weights div:last-child { border-radius: 0 8px 8px 0; }
 .seg-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); gap: 12px; }
 .seg { padding: 18px 20px; }
 .seg-top { display: flex; justify-content: space-between; align-items: baseline; gap: 10px; }
-.seg-w { font-family: "Space Grotesk", sans-serif; font-weight: 700; font-size: 22px; color: var(--accent); }
+.seg-w { font-family: var(--display); font-weight: 700; font-size: 22px; color: var(--accent); }
… 362 more lines

    ↑↓ to move, ↵ to open.