Cannabis Freedom Index

Changelog 8ce76e8

minor updates

8 files of code, design or docs +225 −205 lines

Code, design and documents 8 files

public/favicon.svg +1 −2

Not shown: a picture, a generated file, or past the length shown per change.

src/components/CountryArticle.astro +6 −2
@@ -4,5 +4,5 @@
 import { SEGMENTS, CONTEXT, REC_LABEL, MED_LABEL } from "../data/data.js";
 import { DETAILS } from "../data/details.js";
-import { countries, segAvg, segmentPoints, segmentMax, subunitsOf } from "../lib/countries.js";
+import { countries, segAvg, segmentPoints, segmentMax, subunitsOf, formatDate } from "../lib/countries.js";
 import { tierOf, tierColor } from "../lib/tiers.js";
 
@@ -15,4 +15,7 @@ const d = sub ? null : DETAILS[c.id];
 const countryUrl = `${base}country/${c.slug}/`;
 const unitUrl = (x) => `${countryUrl}${x.id}/`;
+// Date the entry was last reviewed, stored as YYYY-MM-DD and shown in full.
+const updated = sub ? group.reviewed : d?.reviewed;
+const updatedText = updated && formatDate(updated);
 const byName = group ? [...group.units].sort((a, b) => a.name.localeCompare(b.name)) : [];
 const r = 42;
@@ -62,5 +65,5 @@ const circ = 2 * Math.PI * r;
     {sub
       ? <p class="d-hint">{group.intro} Select a segment to show or hide the rules.</p>
-      : <p class="d-hint">Select a segment to show or hide the exact rules and sources.{d && ` Reviewed ${d.reviewed}.`}</p>}
+      : <p class="d-hint">Select a segment to show or hide the exact rules and sources.</p>}
     {sub && SEGMENTS.map((s, i) => (
       <details class="segrow" open>
@@ -165,4 +168,5 @@ const circ = 2 * Math.PI * r;
       </>
     )}
+    {updated && <p class="c-updated">Last updated: <time datetime={updated}>{updatedText}</time></p>}
   </div>
 </article>

src/components/Leaf.astro +2 −3
@@ -1,14 +1,13 @@
 ---
 // Seven-leaflet cannabis leaf, drawn from one leaflet shape rotated and scaled
-// around the point where the leaflets meet the stem.
+// around the point where the leaflets meet. No stem; the fan is centred in the box.
 const { size = 22 } = Astro.props;
 const leaflets = [[0, 1], [-31, 0.9], [31, 0.9], [-63, 0.7], [63, 0.7], [-97, 0.43], [97, 0.43]];
 ---
 <svg viewBox="0 0 24 24" width={size} height={size} aria-hidden="true">
-  <g transform="translate(12 16.4) scale(1.28)" fill="currentColor">
+  <g transform="translate(12 18.25) scale(1.4)" fill="currentColor">
     {leaflets.map(([angle, k]) => (
       <path d="M0 0C1.9-2.6 1.5-7 0-10C-1.5-7-1.9-2.6 0 0Z" transform={`rotate(${angle}) scale(${k})`} />
     ))}
   </g>
-  <path d="M12 16.4V21.6" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" />
 </svg>

src/data/details.js +197 −197
@@ -2,5 +2,5 @@
  *
  * DETAILS[countryId] = {
- *   reviewed: "Month YYYY",
+ *   reviewed: "YYYY-MM-DD",
  *   sources:  { key: [label, url] },
  *   seg:      ten entries in SEGMENTS order, each { t: explanation, src: [source keys] }
@@ -12,5 +12,5 @@
 export const DETAILS = {
   CA: {
-    reviewed: "October 2026",
+    reviewed: "2026-10-04",
     sources: {
       justice: ["Department of Justice Canada — Cannabis legalization and regulation", "https://www.justice.gc.ca/eng/cj-jp/cannabis/"],
@@ -34,5 +34,5 @@ export const DETAILS = {
 
   UY: {
-    reviewed: "October 2026",
+    reviewed: "2026-10-04",
     sources: {
       law: ["Ley N° 19.172 — Regulación y control del cannabis (IMPO)", "https://www.impo.com.uy/bases/leyes/19172-2013"],
@@ -55,5 +55,5 @@ export const DETAILS = {
 
   DE: {
-    reviewed: "October 2026",
+    reviewed: "2026-10-04",
     sources: {
       bmg: ["Bundesgesundheitsministerium — FAQ zum Cannabisgesetz", "https://www.bundesgesundheitsministerium.de/themen/cannabis/faq-cannabisgesetz"],
@@ -76,5 +76,5 @@ export const DETAILS = {
 
   US: {
-    reviewed: "October 2026",
+    reviewed: "2026-10-04",
     sources: {
       ncsl: ["National Conference of State Legislatures — State cannabis laws", "https://www.ncsl.org/health/state-medical-cannabis-laws"],
@@ -98,5 +98,5 @@ export const DETAILS = {
 
   MT: {
-    reviewed: "October 2026",
+    reviewed: "2026-10-04",
     sources: {
       cap628: ["Authority on the Responsible Use of Cannabis Act (Cap. 628)", "https://legislation.mt/eli/cap/628/eng"],
@@ -120,5 +120,5 @@ export const DETAILS = {
 
   JM: {
-    reviewed: "October 2026",
+    reviewed: "2026-10-04",
     sources: {
       fact: ["Ministry of Justice — Dangerous Drugs (Amendment) Act 2015 fact sheet", "https://ncst.gov.jm/wp-content/uploads/2015/09/Ganja-FACT-SHEET-Amendment-to-Dangerous-Drug-ACT.pdf"],
@@ -141,5 +141,5 @@ export const DETAILS = {
 
   ZA: {
-    reviewed: "October 2026",
+    reviewed: "2026-10-04",
     sources: {
       act: ["Cannabis for Private Purposes Act 7 of 2024 — full text", "https://lawlibrary.org.za/akn/za/act/2024/7/eng@2024-06-03"],
@@ -163,5 +163,5 @@ export const DETAILS = {
 
   CZ: {
-    reviewed: "October 2026",
+    reviewed: "2026-10-04",
     sources: {
       expats: ["Expats.cz — Inside Czechia's 2026 cannabis law", "https://www.expats.cz/czech-news/article/inside-czechia-s-2026-cannabis-laws-how-much-can-you-legally-grow-and-possess"],
@@ -185,5 +185,5 @@ export const DETAILS = {
 
   TH: {
-    reviewed: "October 2026",
+    reviewed: "2026-10-04",
     sources: {
       thaiger: ["The Thaiger — Cannabis in Thailand 2026: the new medical-only rules", "https://thethaiger.com/guides/cannabis/cannabis-thailand-2026-medical-rules"],
@@ -206,5 +206,5 @@ export const DETAILS = {
 
   NL: {
-    reviewed: "October 2026",
+    reviewed: "2026-10-04",
     sources: {
       gov: ["Government of the Netherlands — Toleration policy regarding soft drugs and coffee shops", "https://www.government.nl/topics/drugs/toleration-policy-regarding-soft-drugs-and-coffee-shops"],
@@ -227,5 +227,5 @@ export const DETAILS = {
 
   LU: {
-    reviewed: "October 2026",
+    reviewed: "2026-10-04",
     sources: {
       idpc: ["IDPC — Growing and smoking weed at home now legal in Luxembourg", "https://idpc.net/news/2023/07/growing-and-smoking-weed-at-home-now-legal-in-luxembourg"],
@@ -249,5 +249,5 @@ export const DETAILS = {
 
   TT: {
-    reviewed: "October 2026",
+    reviewed: "2026-10-04",
     sources: {
       wiki: ["Wikipedia — Cannabis in Trinidad and Tobago", "https://en.wikipedia.org/wiki/Cannabis_in_Trinidad_and_Tobago"],
@@ -270,5 +270,5 @@ export const DETAILS = {
 
   CH: {
-    reviewed: "October 2026",
+    reviewed: "2026-10-04",
     sources: {
       chch: ["ch.ch (Swiss authorities) — Cannabis", "https://www.ch.ch/en/safety-and-justice/police/cannabis"],
@@ -291,5 +291,5 @@ export const DETAILS = {
 
   CO: {
-    reviewed: "October 2026",
+    reviewed: "2026-10-04",
     sources: {
       wiki: ["Wikipedia — Cannabis in Colombia", "https://en.wikipedia.org/wiki/Cannabis_in_Colombia"],
@@ -313,5 +313,5 @@ export const DETAILS = {
 
   ES: {
-    reviewed: "October 2026",
+    reviewed: "2026-10-04",
     sources: {
       wiki: ["Wikipedia — Cannabis in Spain", "https://en.wikipedia.org/wiki/Cannabis_in_Spain"],
@@ -335,5 +335,5 @@ export const DETAILS = {
 
   AG: {
-    reviewed: "October 2026",
+    reviewed: "2026-10-04",
     sources: {
       wiki: ["Wikipedia — Cannabis in Antigua and Barbuda", "https://en.wikipedia.org/wiki/Cannabis_in_Antigua_and_Barbuda"],
@@ -356,5 +356,5 @@ export const DETAILS = {
 
   PT: {
-    reviewed: "October 2026",
+    reviewed: "2026-10-04",
     sources: {
       law: ["Lei n.º 30/2000 — regime jurídico do consumo de estupefacientes (Diário da República)", "https://diariodarepublica.pt/dr/detalhe/lei/30-2000-599720"],
@@ -378,5 +378,5 @@ export const DETAILS = {
 
   AR: {
-    reviewed: "October 2026",
+    reviewed: "2026-10-04",
     sources: {
       res: ["Resolución 1780/2025, Ministerio de Salud — REPROCANN rules", "https://www.argentina.gob.ar/normativa/nacional/norma-413121/texto"],
@@ -399,5 +399,5 @@ export const DETAILS = {
 
   BZ: {
-    reviewed: "October 2026",
+    reviewed: "2026-10-04",
     sources: {
       act: ["Misuse of Drugs (Amendment) Act 2017, No. 47 of 2017 (PDF, via OAS)", "https://oas.org/ext/Portals/33/adam/Content/1LAvBxqRKUevbza4NS5FZw/Text/Act-No.-47-of-2017-Misuse-of-Drugs-Amendment-Act-2017.pdf"],
@@ -420,5 +420,5 @@ export const DETAILS = {
 
   CL: {
-    reviewed: "October 2026",
+    reviewed: "2026-10-04",
     sources: {
       tni: ["Transnational Institute — Drug law reform in Chile: basic guide", "https://www.tni.org/en/node/16144"],
@@ -441,5 +441,5 @@ export const DETAILS = {
 
   DM: {
-    reviewed: "October 2026",
+    reviewed: "2026-10-04",
     sources: {
       wiki: ["Wikipedia — Cannabis in Dominica", "https://en.wikipedia.org/wiki/Cannabis_in_Dominica"],
@@ -462,5 +462,5 @@ export const DETAILS = {
 
   LC: {
-    reviewed: "October 2026",
+    reviewed: "2026-10-04",
     sources: {
… 1220 more lines
src/data/subunits.js +3 −0
@@ -16,4 +16,5 @@ export const SUBUNITS = {
     label: "State",
     plural: "states",
+    reviewed: "2026-10-04",
     intro: "Federal law still prohibits non-medical cannabis everywhere in the United States; these scores describe state law. Counties and cities can add their own rules, and state law does not apply on federal land.",
     sources: [
@@ -79,4 +80,5 @@ export const SUBUNITS = {
     label: "Province or territory",
     plural: "provinces and territories",
+    reviewed: "2026-10-04",
     intro: "The federal Cannabis Act applies everywhere in Canada. Provinces and territories set the minimum age, where you may consume, how shops work, and whether you may grow at home.",
     sources: [
@@ -104,4 +106,5 @@ export const SUBUNITS = {
     label: "State or territory",
     plural: "states and territories",
+    reviewed: "2026-10-04",
     intro: "Each Australian state and territory has its own drug law. Medical cannabis is regulated federally and is available on prescription everywhere, mostly through telehealth clinics.",
     sources: [

src/lib/countries.js +11 −0
@@ -28,7 +28,18 @@ export const worldAvg = countries.reduce((a, c) => a + c.raw, 0) / countries.len
 import { SUBUNITS } from "../data/subunits.js";
 import { SUBUNIT_DETAILS, unitSource } from "../data/subunit-details.js";
+import { DETAILS } from "../data/details.js";
 
 const scoreOf = (s) => s.reduce((a, v, i) => a + segmentPoints(i, v), 0);
 
+// Review dates are stored as YYYY-MM-DD; this is how they are shown everywhere.
+export const formatDate = (iso) =>
+  new Date(`${iso}T00:00:00Z`).toLocaleDateString("en-GB", { day: "numeric", month: "long", year: "numeric", timeZone: "UTC" });
+
+// The most recent review date across every country and state entry.
+export const lastUpdated = [
+  ...Object.values(DETAILS).map((d) => d.reviewed),
+  ...Object.values(SUBUNITS).map((g) => g.reviewed),
+].filter(Boolean).sort().at(-1);
+
 // For a country id, returns { label, plural, intro, sources, units } with each unit scored,
 // ranked within its country, and placed where it would sit among countries. Undefined if none.

src/pages/index.astro +2 −1
@@ -4,5 +4,5 @@ import DidYouKnow from "../components/DidYouKnow.astro";
 import Lore from "../components/Lore.astro";
 import { SEGMENTS, DATA_SNAPSHOT, REC_LABEL, MED_LABEL } from "../data/data.js";
-import { countries, regions, worldAvg } from "../lib/countries.js";
+import { countries, regions, worldAvg, lastUpdated, formatDate } from "../lib/countries.js";
 import { TIERS, tierColor } from "../lib/tiers.js";
 
@@ -119,4 +119,5 @@ const mapData = countries.map(({ id, num, name, flag, raw, score, rank, s }) =>
         </table>
       </div>
+      <p class="table-updated">Last updated: <time datetime={lastUpdated}>{formatDate(lastUpdated)}</time></p>
     </section>
 

src/styles/global.css +3 −0
@@ -427,2 +427,5 @@ td.num, th.num { width: 52px; color: var(--muted); }
 .u-score { text-align: right; font-weight: 600; font-variant-numeric: tabular-nums; }
 @media (max-width: 640px) { .units { columns: 1; } }
+
+.c-updated { margin: 28px 0 0; padding-top: 14px; border-top: 1px solid var(--border); color: var(--muted); font-size: 13px; }
+.table-updated { margin: 12px 4px 0; color: var(--muted); font-size: 13px; text-align: right; }

    ↑↓ to move, ↵ to open.