Redesign homepage: navy and pink 'sentence is the layout' direction

Complete rebuild of the single page from the design-taste-frontend skill
(direction: sentence-as-layout, seed 1084447843). CSS and JS moved out of
the markup into css/site.css and js/site.js.

- navy field #1a2039 with pink ink #f9a3c0: no Odoo plum, no teal, no violet
- hero headline carries a 1689 world map inside the sentence
- claims as full-bleed switchable bands, tips table, module picker
- four archival Wikimedia pictures, credited in the footer
- inspector: 0 FAIL at 1440 / 768 / 390 (lint clean)
This commit is contained in:
Oliver committed 2026-10-23 14:26:27 +00:00
1 parent ed6d3c747b
commit 94eb541ac3
9 files changed
+1185 -783

No files matched your search

+3
View File
@@ -0,0 +1,3 @@
.taste-skill/
node_modules/
.DS_Store
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 98 KiB

+90
View File
@@ -0,0 +1,90 @@
[
{
"file": "assets/world-map-1689.jpg",
"media": "image",
"ref": "commons:1417142",
"title": "World Map 1689",
"creator": "Gerard van Schagen",
"creatorUrl": null,
"date": "This edition 1689",
"license": "public domain",
"licenseCode": "pd",
"licenseUrl": "https://creativecommons.org/publicdomain/mark/1.0/",
"creditRequired": false,
"page": "https://commons.wikimedia.org/wiki/File:World_Map_1689.JPG",
"via": "Wikimedia Commons",
"image": "https://thumb.wikimedia.org/wikipedia/commons/thumb/3/3b/World_Map_1689.JPG/1920px-World_Map_1689.JPG",
"width": 1920,
"height": 1657,
"bytes": 1780114,
"credit": "\"World Map 1689\" by Gerard van Schagen, public domain, via Wikimedia Commons",
"notes": [],
"saved": "2026-10-23T14:13:19.072Z"
},
{
"file": "assets/a-general-map-of-the-world-or.jpg",
"media": "image",
"ref": "commons:14675675",
"title": "A General Map of the World, or Terraqueous Globe with all the New Discoveries and Marginal Delineations, Containing the Most Interesting Particulars in the Solar, Starry and Mundane System .",
"creator": "Thomas Kitchin",
"creatorUrl": null,
"date": "1794",
"license": "public domain",
"licenseCode": "pd",
"licenseUrl": "https://creativecommons.org/publicdomain/mark/1.0/",
"creditRequired": false,
"page": "https://commons.wikimedia.org/wiki/File:1794_Samuel_Dunn_Wall_Map_of_the_World_in_Hemispheres_-_Geographicus_-_World2-dunn-1794.jpg",
"via": "Wikimedia Commons",
"image": "https://thumb.wikimedia.org/wikipedia/commons/thumb/f/ff/1794_Samuel_Dunn_Wall_Map_of_the_World_in_Hemispheres_-_Geographicus_-_World2-dunn-1794.jpg/1920px-1794_Samuel_Dunn_Wall_Map_of_the_World_in_Hemispheres_-_Geographicus_-_World2-dunn-1794.jpg",
"width": 1920,
"height": 1617,
"bytes": 1596707,
"credit": "\"A General Map of the World, or Terraqueous Globe with all the New Discoveries and Margina…\" by Thomas Kitchin, public domain, via Wikimedia Commons",
"notes": [],
"saved": "2026-10-23T14:13:19.613Z"
},
{
"file": "assets/a-printer-s-workshop-on-the-left.jpg",
"media": "image",
"ref": "commons:36562906",
"title": "A printer's workshop: on the left a printing press, on the r",
"creator": null,
"creatorUrl": null,
"date": null,
"license": "CC BY 4.0",
"licenseCode": "by",
"licenseUrl": "https://creativecommons.org/licenses/by/4.0",
"creditRequired": true,
"page": "https://commons.wikimedia.org/wiki/File:A_printer%27s_workshop;_on_the_left_a_printing_press,_on_the_r_Wellcome_V0023751.jpg",
"via": "Wikimedia Commons",
"image": "https://thumb.wikimedia.org/wikipedia/commons/thumb/d/d7/A_printer%27s_workshop%3B_on_the_left_a_printing_press%2C_on_the_r_Wellcome_V0023751.jpg/1920px-A_printer%27s_workshop%3B_on_the_left_a_printing_press%2C_on_the_r_Wellcome_V0023751.jpg",
"width": 1920,
"height": 667,
"bytes": 1121882,
"credit": "\"A printer's workshop: on the left a printing press, on the r\", CC BY 4.0, via Wikimedia Commons",
"notes": [],
"saved": "2026-10-23T14:13:20.157Z"
},
{
"file": "assets/geography-four-types-of-globe-engraving.jpg",
"media": "image",
"ref": "commons:36574036",
"title": "Geography: four types of globe. Engraving.",
"creator": null,
"creatorUrl": null,
"date": null,
"license": "CC BY 4.0",
"licenseCode": "by",
"licenseUrl": "https://creativecommons.org/licenses/by/4.0",
"creditRequired": true,
"page": "https://commons.wikimedia.org/wiki/File:Geography;_four_types_of_globe._Engraving._Wellcome_V0025077.jpg",
"via": "Wikimedia Commons",
"image": "https://thumb.wikimedia.org/wikipedia/commons/thumb/6/6a/Geography%3B_four_types_of_globe._Engraving._Wellcome_V0025077.jpg/1920px-Geography%3B_four_types_of_globe._Engraving._Wellcome_V0025077.jpg",
"width": 1920,
"height": 3129,
"bytes": 3000015,
"credit": "\"Geography: four types of globe. Engraving.\", CC BY 4.0, via Wikimedia Commons",
"notes": [],
"saved": "2026-10-23T14:13:20.762Z"
}
]
Binary file not shown.

After

Width:  |  Height:  |  Size: 557 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 678 KiB

+735
View File
@@ -0,0 +1,735 @@
/* ============================================================
The OC Guy — Odoo Community tips and tricks
Direction: "the sentence is the layout" (seed 1084447843)
Palette: navy field, pink ink. No Odoo plum, no teal, no violet.
============================================================ */
:root {
/* colour roles */
--bg: #1a2039;
--surface: #212846;
--ink: #f9a3c0;
--muted: #b9879c;
--accent: #f9a3c0;
--accent-ink: #1a2039;
/* type steps — five, no more */
--t-small: clamp(13px, 0.8rem + 0.1vw, 14px);
--t-body: clamp(17px, 1rem + 0.25vw, 19px);
--t-statement: clamp(26px, 2.35vw, 36px);
--t-head: clamp(32px, 1.3rem + 3.2vw, 64px);
--t-display: clamp(38px, 6.1vw, 90px);
--pad: clamp(16px, 3vw, 32px);
--gap-section: clamp(72px, 7.5vw, 112px);
--font: "General Sans", ui-sans-serif, system-ui, -apple-system, "Helvetica Neue", Arial, sans-serif;
--ease: cubic-bezier(0.2, 0.8, 0.2, 1);
}
*, *::before, *::after { box-sizing: border-box; }
html {
-webkit-text-size-adjust: 100%;
scroll-behavior: smooth;
}
body {
margin: 0;
background: var(--bg);
color: var(--ink);
font-family: var(--font);
font-size: var(--t-body);
line-height: 1.45;
font-weight: 400;
overflow-x: hidden;
}
img { display: block; max-width: 100%; height: auto; }
a { color: inherit; }
button, input { font: inherit; color: inherit; }
:focus-visible {
outline: 2px solid var(--ink);
outline-offset: 4px;
}
::selection { background: var(--ink); color: var(--bg); }
.sr-only {
position: absolute; width: 1px; height: 1px;
padding: 0; margin: -1px; overflow: hidden;
clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}
.skip {
position: fixed; top: 8px; left: 8px; z-index: 60;
padding: 10px 14px; background: var(--ink); color: var(--bg);
font-size: var(--t-small); text-decoration: none;
transform: translateY(-160%);
transition: transform 240ms var(--ease);
}
.skip:focus { transform: translateY(0); }
/* ---------- top bar: wordmark left, links spread right ---------- */
.topbar {
display: flex;
align-items: baseline;
justify-content: space-between;
gap: 24px;
padding: 24px var(--pad) 0;
}
.mark {
font-size: var(--t-small);
font-weight: 500;
text-decoration: none;
letter-spacing: -0.01em;
}
.nav {
display: flex;
flex-wrap: wrap;
gap: clamp(12px, 2.4vw, 40px);
font-size: var(--t-small);
}
.nav a { text-decoration: none; color: var(--muted); }
.nav a:hover, .nav a:focus-visible { color: var(--ink); }
.nav .nav-action { color: var(--ink); }
/* ---------- hero ---------- */
.hero {
min-height: 92svh;
display: flex;
flex-direction: column;
justify-content: center;
padding: clamp(56px, 9vh, 110px) var(--pad) 32px;
}
.hero-part { white-space: nowrap; }
.hero-line {
margin: 0;
display: flex;
flex-wrap: wrap;
align-items: baseline;
gap: 0 0.2em;
font-size: var(--t-display);
font-weight: 700;
letter-spacing: -0.035em;
line-height: 0.94;
}
/* the photograph set into the sentence, one line tall */
.slot {
display: inline-block;
width: 2.8em;
height: 0.76em;
vertical-align: 0;
overflow: hidden;
background: var(--surface);
}
.slot img {
width: 100%; height: 100%;
object-fit: cover;
object-position: 50% 52%;
}
.hero-foot {
margin-top: clamp(40px, 7vh, 88px);
display: grid;
grid-template-columns: repeat(12, 1fr);
gap: var(--pad);
align-items: end;
}
.hero-say {
grid-column: 5 / 11;
margin: 0;
max-width: 34em;
font-size: var(--t-body);
line-height: 1.5;
}
.hero-foot .btn { grid-column: 11 / 13; justify-self: end; }
/* ---------- buttons: one shape, square, filled ---------- */
.btn {
display: inline-flex;
align-items: center;
justify-content: center;
min-height: 48px;
padding: 0 26px;
background: var(--accent);
color: var(--accent-ink);
font-size: var(--t-small);
font-weight: 500;
text-decoration: none;
border: 0;
border-radius: 0;
cursor: pointer;
transition: transform 200ms var(--ease), background-color 200ms var(--ease);
}
.btn:hover { background: var(--ink); transform: translateY(-2px); }
.btn:active { transform: translateY(0); }
/* ---------- intro: statement with inline thumbnails ---------- */
.intro {
padding: clamp(56px, 6vw, 96px) var(--pad) clamp(80px, 9vw, 144px);
display: flex;
justify-content: center;
}
.statement {
margin: 0;
max-width: 21em;
font-size: var(--t-statement);
line-height: 1.18;
letter-spacing: -0.015em;
font-weight: 500;
}
.thumb {
display: inline-block;
width: 1.7em;
height: 1em;
margin: 0 0.12em;
vertical-align: -0.1em;
overflow: hidden;
border-radius: 0.06em;
background: var(--surface);
}
.thumb img { width: 100%; height: 100%; object-fit: cover; }
.thumb img { object-position: 50% 40%; }
/* ---------- open: map to full width ---------- */
.open { padding-bottom: var(--gap-section); overflow: clip; }
.map-figure { margin: 0; overflow: clip; }
.map-figure img {
width: 100%;
max-width: 100%;
height: clamp(220px, 30vw, 420px);
object-fit: cover;
object-position: 50% 45%;
background: var(--surface);
}
.map-figure figcaption {
padding: 14px var(--pad) 0;
font-size: var(--t-small);
color: var(--muted);
max-width: 52em;
}
.open-copy {
margin-top: clamp(48px, 6vw, 88px);
padding: 0 var(--pad);
display: grid;
grid-template-columns: repeat(12, 1fr);
gap: var(--pad);
}
.open-copy h2 {
grid-column: 1 / 7;
margin: 0;
font-size: var(--t-head);
font-weight: 700;
letter-spacing: -0.03em;
line-height: 0.98;
}
.open-copy p {
grid-column: 8 / 13;
margin: 0;
max-width: 30em;
line-height: 1.55;
}
.open-figure {
grid-column: 10 / 13;
margin: clamp(32px, 4vw, 56px) 0 0;
}
.open-figure img {
width: 100%;
aspect-ratio: 4 / 5;
object-fit: cover;
object-position: 50% 38%;
background: var(--surface);
}
/* ---------- claims: sentences with switches ---------- */
.claims {
background: var(--surface);
padding: clamp(24px, 3vw, 40px) 0 calc(var(--gap-section) * 0.6);
}
.band {
border: 0;
background: transparent;
transition: background-color 400ms var(--ease);
padding: 0 var(--pad);
}
.band[data-on="true"] { background: var(--bg); }
.band-switch {
display: grid;
grid-template-columns: 1fr auto;
align-items: center;
gap: 24px;
width: 100%;
min-height: clamp(112px, 17vh, 168px);
padding: 18px 0;
background: none;
border: 0;
text-align: left;
cursor: pointer;
}
.band-text {
font-size: var(--t-statement);
font-weight: 500;
letter-spacing: -0.03em;
line-height: 1;
color: var(--muted);
transition: color 300ms var(--ease);
}
.band[data-on="true"] .band-text { color: var(--ink); }
.track {
position: relative;
display: block;
width: 2.4em;
height: 1.15em;
min-width: 52px;
min-height: 26px;
background: var(--bg);
transition: background-color 300ms var(--ease);
}
.band[data-on="true"] .track { background: var(--ink); }
.knob {
position: absolute;
top: 0.14em;
left: 0.14em;
width: calc(1.15em - 0.28em);
height: calc(1.15em - 0.28em);
min-width: 18px;
min-height: 18px;
background: var(--muted);
transition: transform 300ms var(--ease), background-color 300ms var(--ease);
}
.band[data-on="true"] .knob {
transform: translateX(1.25em);
background: var(--bg);
}
.band-value {
margin: 0;
max-width: 46em;
padding: 0 0 22px;
font-size: var(--t-body);
line-height: 1.5;
color: var(--muted);
opacity: 0.6;
transition: opacity 300ms var(--ease), color 300ms var(--ease);
}
.band[data-on="true"] .band-value { opacity: 1; color: var(--ink); }
.band-value code {
font-family: var(--font);
font-weight: 500;
color: var(--ink);
}
/* ---------- tips: statement left, table pushed right ---------- */
.tips { padding: var(--gap-section) 0; }
.tips h2 {
margin: 0 0 96px;
padding-left: var(--pad);
padding-right: var(--pad);
font-size: var(--t-head);
font-weight: 700;
letter-spacing: -0.035em;
line-height: 0.96;
max-width: 15em;
}
.tips h2::first-line { padding-left: 3vw; }
.tips-grid {
display: grid;
grid-template-columns: repeat(12, 1fr);
gap: var(--pad);
padding: 0 var(--pad);
}
.tips-side { grid-column: 1 / 6; }
.tips-note {
margin: 0 0 40px;
max-width: 24em;
color: var(--muted);
line-height: 1.55;
}
/* the live thing */
.picker {
background: var(--surface);
padding: clamp(18px, 2vw, 28px);
max-width: 30em;
}
.picker-q {
margin: 0 0 16px;
font-size: var(--t-small);
color: var(--muted);
}
.chips {
display: flex;
flex-wrap: wrap;
gap: 8px;
}
.chip {
padding: 10px 14px;
min-height: 40px;
background: var(--bg);
color: var(--ink);
border: 0;
border-radius: 0;
font-size: var(--t-small);
cursor: pointer;
transition: background-color 180ms var(--ease), color 180ms var(--ease), transform 180ms var(--ease);
}
.chip:hover { transform: translateY(-1px); }
.chip[aria-pressed="true"] { background: var(--ink); color: var(--bg); }
.picker-out {
margin: 20px 0 0;
font-size: var(--t-body);
line-height: 1.4;
min-height: 2.8em;
color: var(--ink);
}
.picker-out .mod { font-weight: 700; }
.picker-out .arrow { color: var(--muted); }
.tips-figure {
margin: clamp(28px, 4vw, 48px) 0 0;
width: min(100%, 22em);
}
.tips-figure img {
width: 100%;
aspect-ratio: 4 / 5;
object-fit: cover;
object-position: 50% 42%;
background: var(--surface);
}
.tips-list {
grid-column: 8 / 13;
margin: 0;
padding: 0;
list-style: none;
}
.tips-list li {
display: grid;
grid-template-columns: 7.5em 1fr;
gap: 4px 16px;
padding-bottom: 26px;
font-size: var(--t-body);
}
.tips-list li:nth-child(4) { padding-top: 18px; }
.tip-kind { color: var(--muted); font-size: var(--t-small); padding-top: 3px; }
.tip-what { line-height: 1.35; }
.tip-where {
grid-column: 2;
color: var(--muted);
font-size: var(--t-small);
text-decoration: none;
}
a.tip-where { color: var(--ink); text-underline-offset: 3px; text-decoration: underline; }
a.tip-where:hover { color: var(--bg); background: var(--ink); }
/* ---------- about: portrait as drop cap ---------- */
.about {
padding: var(--gap-section) var(--pad);
display: grid;
grid-template-columns: repeat(12, 1fr);
grid-template-areas:
"head head head head head head head head head head head head"
"bio bio bio bio bio bio bio bio bio . . ."
"facts facts facts facts . . . . . . . .";
gap: 0 var(--pad);
}
.about-facts {
grid-area: facts;
margin: 40px 0 0;
max-width: 32em;
display: flex;
flex-direction: column;
gap: 10px;
font-size: var(--t-small);
color: var(--muted);
}
.about-facts a { color: var(--ink); }
.about h2 {
grid-area: head;
margin: 0 0 28px;
font-size: var(--t-head);
font-weight: 700;
letter-spacing: -0.03em;
line-height: 1;
}
.bio {
grid-area: bio;
margin: 0;
max-width: 26em;
font-size: var(--t-statement);
line-height: 1.22;
letter-spacing: -0.01em;
font-weight: 400;
}
.dropcap {
float: left;
width: 5em;
height: 5em;
margin: 0.1em 0.5em 0.2em 0;
object-fit: cover;
object-position: 30% 40%;
background: var(--surface);
}
/* ---------- ask: a sentence with a blank ---------- */
.ask {
background: var(--surface);
padding: var(--gap-section) var(--pad);
max-width: 100%;
}
.ask-line {
margin: 0;
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 0.22em;
font-size: var(--t-head);
font-weight: 700;
letter-spacing: -0.03em;
line-height: 1.1;
}
.ask-line label { flex: 0 0 auto; }
.ask-line input {
flex: 1 1 7em;
min-width: 6em;
height: 1.2em;
padding: 0 0.2em;
background: var(--surface);
border: 0;
border-radius: 0;
font-size: 0.5em;
font-weight: 500;
letter-spacing: 0;
}
.ask-line input::placeholder { color: var(--muted); }
.ask-send {
flex: 0 0 auto;
height: 1.05em;
padding: 0 0.4em;
background: var(--accent);
color: var(--accent-ink);
border: 0;
border-radius: 0;
font-size: 0.5em;
font-weight: 500;
letter-spacing: 0;
cursor: pointer;
transition: background-color 180ms var(--ease), transform 180ms var(--ease);
}
.ask-send:hover { background: var(--ink); transform: translateY(-1px); }
.ask-note {
margin: 28px 0 0;
font-size: var(--t-small);
color: var(--muted);
max-width: 40em;
}
/* ---------- footer: invitation over a cropped name ---------- */
.foot {
background: var(--ink);
color: var(--bg);
padding: clamp(56px, 7vw, 96px) var(--pad) 0;
overflow: hidden;
min-height: 88svh;
display: flex;
flex-direction: column;
}
.foot-top {
display: grid;
grid-template-columns: repeat(12, 1fr);
gap: var(--pad);
align-items: start;
}
.foot-invite {
grid-column: 1 / 8;
margin: 0;
font-size: var(--t-head);
font-weight: 700;
letter-spacing: -0.035em;
line-height: 0.98;
max-width: 12em;
}
.foot-top .btn {
grid-column: 10 / 13;
justify-self: end;
background: var(--bg);
color: var(--ink);
}
.foot-top .btn:hover { background: var(--surface); color: var(--ink); }
.foot-links {
margin-top: clamp(40px, 6vw, 80px);
display: flex;
flex-wrap: wrap;
gap: 24px;
font-size: var(--t-body);
}
.foot-links a { text-decoration: underline; text-underline-offset: 4px; }
.foot-links a:hover { text-decoration-thickness: 2px; }
.foot-credits {
margin: 24px 0 0;
font-size: var(--t-small);
line-height: 1.5;
max-width: 62em;
opacity: 0.9;
}
.foot-credits a { text-underline-offset: 2px; }
.foot-name {
margin: auto 0 0;
font-size: clamp(64px, 20vw, 280px);
font-weight: 700;
letter-spacing: -0.05em;
line-height: 0.8;
white-space: nowrap;
transform: translateY(22%);
user-select: none;
}
/* ---------- motion ---------- */
html.js [data-rv] {
opacity: 0;
transform: translateY(22px);
transition: opacity 620ms var(--ease), transform 620ms var(--ease);
}
html.js [data-rv].rv-in { opacity: 1; transform: none; }
html.js [data-rv="2"] { transition-delay: 70ms; }
html.js [data-rv="3"] { transition-delay: 140ms; }
html.js [data-rv="4"] { transition-delay: 210ms; }
/* signature move: the shutter on the hero photograph */
html.js .slot { clip-path: inset(0 100% 0 0); }
html.js .hero-line.shutter .slot {
clip-path: inset(0 0 0 0);
transition: clip-path 1100ms cubic-bezier(0.16, 1, 0.3, 1);
}
html.js .slot img { transform: scale(1.12); transition: transform 1600ms cubic-bezier(0.16, 1, 0.3, 1); }
html.js .hero-line.shutter .slot img { transform: scale(1); }
@media (prefers-reduced-motion: reduce) {
html { scroll-behavior: auto; }
html.js [data-rv] { opacity: 1; transform: none; transition: none; }
html.js .slot, html.js .hero-line.shutter .slot { clip-path: none; transition: none; }
html.js .slot img, html.js .hero-line.shutter .slot img { transform: none; transition: none; }
.map-figure img { transform: none !important; }
}
/* ---------- narrow screens ---------- */
@media (max-width: 900px) {
.hero-foot { grid-template-columns: 1fr; gap: 24px; }
.hero-say { grid-column: 1 / -1; }
.hero-foot .btn { grid-column: 1 / -1; justify-self: start; }
.open-copy h2,
.open-copy p,
.open-figure { grid-column: 1 / -1; }
.open-figure { width: min(100%, 24em); }
.tips-side,
.tips-list { grid-column: 1 / -1; }
.tips-note { margin-bottom: 28px; }
.about h2, .bio, .about-facts { grid-column: 1 / -1; }
.foot-invite { grid-column: 1 / -1; }
.foot-top .btn { grid-column: 1 / -1; justify-self: start; margin-top: 28px; }
.foot { min-height: auto; }
}
@media (max-width: 700px) {
.hero-line {
flex-direction: column;
align-items: flex-start;
gap: 14px;
font-size: clamp(26px, 7.6vw, 34px);
line-height: 1.04;
}
.slot {
width: 1.7em;
height: 0.7em;
vertical-align: 0;
}
.about {
grid-template-areas:
"head head head head head head head head head head head head"
"bio bio bio bio bio bio bio bio bio bio bio bio"
"facts facts facts facts facts facts facts facts facts facts facts facts";
gap: 0;
}
.about-facts { flex-direction: row; flex-wrap: wrap; gap: 6px 18px; margin: 28px 0 0; }
}
@media (max-width: 620px) {
.topbar { padding-top: 18px; }
.nav { gap: 14px; font-size: 13px; }
.nav a:not(.nav-action):not(:first-child) { display: none; }
.hero { padding-top: 96px; }
.hero-line { line-height: 0.98; }
.slot { width: 1.5em; height: 0.6em; }
.statement { font-size: 22px; line-height: 1.25; }
.statement .thumb:nth-of-type(2) { display: none; }
.band-switch { min-height: 132px; gap: 16px; }
.band-text { line-height: 1.06; }
.tips h2 { margin-bottom: 56px; }
.tips-list li { grid-template-columns: 1fr auto; padding-bottom: 22px; }
.tip-kind { grid-column: 1; }
.tip-what { grid-column: 1 / -1; }
.tip-where { grid-column: 1 / -1; }
.dropcap { width: 3.2em; height: 3.2em; }
.bio { font-size: 22px; line-height: 1.28; }
.ask-line { font-size: var(--t-statement); }
.ask-line label { flex: 1 1 100%; }
.ask-line input { flex: 1 1 100%; order: 3; height: 2.4em; font-size: 0.8em; }
.ask-send { order: 4; height: 2em; font-size: 0.8em; }
.foot-name { font-size: 26vw; }
}
+209 -783
View File
File diff suppressed because it is too large. Load diff
+148
View File
@@ -0,0 +1,148 @@
/* The OC Guy — page behaviour.
Everything here degrades: without JS the page still reads, the bands still
show their titles, the tips still list, the form still shows. */
(function () {
'use strict';
var doc = document.documentElement;
doc.classList.add('js');
var reduce = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
/* ---------- signature move: the shutter on the hero photograph ---------- */
var hero = document.querySelector('.hero-line');
if (hero) {
if (reduce) {
hero.classList.add('shutter');
} else {
requestAnimationFrame(function () {
setTimeout(function () { hero.classList.add('shutter'); }, 120);
});
}
}
/* ---------- entrance for the parts of every section ---------- */
var targets = [];
document.querySelectorAll('.intro .statement, .open h2, .open p, .map-figure figcaption, .tips h2, .tips-note, .picker, .tips-list li, .about h2, .bio, .about-facts, .ask-line, .ask-note, .band-text, .foot-invite, .foot-links').forEach(function (el) {
targets.push(el);
});
if (!reduce && 'IntersectionObserver' in window) {
var io = new IntersectionObserver(function (entries) {
entries.forEach(function (entry) {
if (!entry.isIntersecting) return;
entry.target.classList.add('rv-in');
io.unobserve(entry.target);
});
}, { rootMargin: '0px 0px -12% 0px', threshold: 0.12 });
targets.forEach(function (el, i) {
el.setAttribute('data-rv', String((i % 4) + 1));
io.observe(el);
});
} else {
targets.forEach(function (el) { el.classList.add('rv-in'); });
}
/* ---------- switches: five claims ---------- */
document.querySelectorAll('.band-switch').forEach(function (btn) {
btn.addEventListener('click', function () {
var band = btn.closest('.band');
var on = btn.getAttribute('aria-checked') === 'true';
btn.setAttribute('aria-checked', String(!on));
band.setAttribute('data-on', String(!on));
});
});
/* ---------- the live thing: pick what the company does ---------- */
var chips = Array.prototype.slice.call(document.querySelectorAll('.chip'));
var out = document.querySelector('.picker-out');
var installOrder = ['Sales', 'CRM', 'Purchase', 'Manufacturing', 'Inventory', 'Project', 'Timesheets', 'Expenses', 'Invoicing', 'Accounting'];
function render(mods) {
if (!mods.length) {
out.textContent = 'Choose one, or several. The modules stack in the order you would install them.';
return;
}
out.innerHTML = '';
mods.forEach(function (name, i) {
var span = document.createElement('span');
span.className = 'mod';
span.textContent = name;
out.appendChild(span);
if (i < mods.length - 1) {
var arrow = document.createElement('span');
arrow.className = 'arrow';
arrow.textContent = ' → ';
out.appendChild(arrow);
}
});
var note = document.createElement('span');
note.className = 'arrow';
note.textContent = ' — that order, top to bottom.';
out.appendChild(note);
}
chips.forEach(function (chip) {
chip.setAttribute('aria-pressed', 'false');
chip.addEventListener('click', function () {
var pressed = chip.getAttribute('aria-pressed') === 'true';
chip.setAttribute('aria-pressed', String(!pressed));
var picked = chips.filter(function (c) { return c.getAttribute('aria-pressed') === 'true'; })
.reduce(function (all, c) {
c.dataset.modules.split(',').forEach(function (m) {
var name = m.trim();
if (all.indexOf(name) === -1) all.push(name);
});
return all;
}, []);
picked.sort(function (a, b) { return installOrder.indexOf(a) - installOrder.indexOf(b); });
render(picked);
});
});
/* ---------- ask: one question, by mail ---------- */
var send = document.querySelector('.ask-send');
var mail = document.getElementById('ask-mail');
if (send && mail) {
send.addEventListener('click', function () {
var addr = (mail.value || '').trim();
var body = 'My question about Odoo Community:\n\n\n';
if (addr) body += '\n— reply to: ' + addr + '\n';
var href = 'mailto:o.arnold@projektbox.de'
+ '?subject=' + encodeURIComponent('Odoo Community question')
+ '&body=' + encodeURIComponent(body);
if (addr && addr.indexOf('@') === -1) {
mail.focus();
mail.setAttribute('aria-invalid', 'true');
return;
}
mail.removeAttribute('aria-invalid');
window.location.href = href;
});
mail.addEventListener('keydown', function (e) {
if (e.key === 'Enter') send.click();
});
}
/* ---------- one moving picture: the world map drifts against the scroll ---------- */
var map = document.getElementById('worldmap');
if (map && !reduce) {
var ticking = false;
var update = function () {
var rect = map.getBoundingClientRect();
var vh = window.innerHeight || 800;
if (rect.bottom > -200 && rect.top < vh + 200) {
var progress = (rect.top + rect.height / 2 - vh / 2) / vh;
map.style.transform = 'translate3d(0,' + (progress * -26).toFixed(2) + 'px,0) scale(1.06)';
}
ticking = false;
};
window.addEventListener('scroll', function () {
if (!ticking) { ticking = true; requestAnimationFrame(update); }
}, { passive: true });
update();
}
})();