ChronosoPHIa: "Facing the Fear of Time Not by Running Away, But by Organizing It Through the Golden Ratio."

by shredermann in Design > Software

203 Views, 1 Favorites, 0 Comments

ChronosoPHIa: "Facing the Fear of Time Not by Running Away, But by Organizing It Through the Golden Ratio."

chrono4.png
chrono.gif

The Golden Awakening


φ = 1.61803398875…


"Facing the fear of time not by running away, but by organizing it through the Golden Ratio."


"From Chronophobia to ChronosoPHIa: a journey from anxiety to wisdom."


My Fear: Time Is Not Coming Back


I have always had a complicated relationship with time. Not the abstract, philosophical kind , the visceral, daily kind. The feeling of watching a deadline approach while being paralyzed. The awareness that days pass faster each year. The weight of unfinished projects piling up. In psychology, this is called chronophobia: the persistent anxiety caused by the passage of time.

For me it was both emotional and rational. I knew intellectually that time lost cannot be recovered. Every hour spent on procrastination is gone permanently. Yet knowing this did not stop the anxiety, it amplified it. The more I understood time's finality, the more paralyzed I became.

The turning point came when I crossed a mathematical threshold I had not anticipated: 61.8% of my estimated lifespan. This is 1/φ, the golden ratio reciprocal, applied to life itself. At this point, the time I have lived is in perfect golden proportion to the time remaining. Something shifted. Instead of seeing the past as lost, I began seeing it as the larger part of a harmonic structure. And the remaining 38.2%, not as what is running out, but as what must be used wisely.

That realization became ChronosoPHIa: a tool to face time directly, without panic, by giving it the most harmonious structure in mathematics.


Supplies

What You Need

  1. A text editor (VS Code, Notepad++, or any plain text editor)
  2. A modern web browser (Chrome, Firefox, Safari, Edge)
  3. Nothing else — no installation, no server, no dependencies

The Concept: Why Φ?

chrono5.png

The Concept: Why φ?


The Golden Ratio (φ ≈ 1.618) is not just an aesthetic curiosity. It is a mathematical constant that appears in nautilus shells, sunflower spirals, galaxy arms, and the proportions of living organisms. It represents self-similar harmony, the pattern that feels right at every scale.

My hypothesis was simple: if anxiety about time comes from its apparent chaos and irreversibility, then imposing φ-structure on how we visualize time might transform that anxiety into clarity. Not by lying about time's passage, but by finding beauty in its proportions.

The Four Zones

ChronosoPHIa divides life into four zones whose visual heights follow the golden cascade:

  1. PAST — Accumulated Experience: the largest zone, dominant, weighted with meaning
  2. PRESENT — Harmony (φ): the arc showing where you stand in the golden structure
  3. FUTURE — Golden Potential: what remains to invest
  4. PROJECT — Target Action: a specific deadline, the immediate horizon


Each zone is 1/φ times the height of the one above it. The structure is not arbitrary, it mirrors the proportions of a golden rectangle, one of the most visually satisfying forms in geometry.

The Golden Age Threshold

The critical mathematical event in ChronosoPHIa is crossing 61.8% of your estimated lifespan (using 80 years as a baseline). At this point:

past ÷ remaining = φ ←→ 61.8% lived · 38.2% remaining

When this threshold is crossed, the interface transitions into Golden Era mode, a slow, 2-second CSS transformation that warms the entire color palette from cold dark blue to deep golden amber. The message changes from "Wisdom in the making..." to "Welcome to your Golden Age."

For me personally, this transition was not just visual. It became a commitment: no more procrastination, no more projects abandoned halfway. The Golden Era is not a reward, it is a responsibility.


Building ChronosoPHIa

chrono6.png
chrono5.png
chrono3.png
chrono2.png
chrono1.png

ChronosoPHIa is a single HTML file. No framework. No npm. No build step. This was a deliberate choice: the tool should be as immediate and frictionless as the insight it tries to deliver. You open a file. You face your time.

The file has three parts:

  1. HTML — four zone divs stacked vertically, plus two date inputs
  2. CSS — φ-proportioned heights as custom properties, plus the Golden Era color transition
  3. JavaScript — one update() function, one particle class, one setInterval


Key Code: The φ Layout

The zone heights are defined as CSS custom properties:

:root {
--zone-past: 295px; /* largest — 295/720 ≈ past weight */
--zone-present: 183px; /* 295 / φ ≈ 183 */
--zone-future: 113px; /* 183 / φ ≈ 113 */
--zone-project: 129px; /* remaining */
}


Key Code: The Life Calculation

The core math runs every second:

const livedDays = Math.floor((now - birthDate) / 86400000);
const age = livedDays / 365.25;
const pctLife = Math.min((age / EXPECTANCY) * 100, 100);
const yearsLeft = Math.max(0, EXPECTANCY - age);


Key Code: The Arc Visualisation

The semicircular arc in Zone PRESENT uses SVG with stroke-dashoffset to animate the fill. The total arc length is 345px (half-circumference of radius 110):

// Arc fill: 0% = fully offset (empty), 100% = no offset (full)
arcElement.style.strokeDashoffset = 345 - (345 * (pctLife / 100));


The φ marker is positioned on the arc using polar coordinates:

const angle = Math.PI * (1 - 0.618033); // 61.8% of π
marker.style.left = (150 + 110 * Math.cos(angle) - 10) + 'px';
marker.style.top = (120 - 110 * Math.sin(angle) - 20) + 'px';


Key Code: The Golden Era Transition

When life percentage crosses 61.8%, a single class is added to the device div. CSS handles the rest with a 2-second smooth transition:

if (pctLife >= 61.8) {
device.classList.add('golden-era');
msgEl.innerText = 'Welcome to your Golden Age.';
}


The CSS transition:

.device { transition: all 2s ease-in-out; }
.golden-era { --bg: #1a160a; --gold: #e8c97e; --border: #c8a96e; }


Key Code: The Sand Particles

A canvas overlay creates falling gold particles, a digital hourglass. Each particle is independent, with random speed, size, and opacity:

class Particle {
reset() {
this.x = Math.random() * canvas.width;
this.y = Math.random() * -canvas.height; // start above screen
this.vy = 0.5 + Math.random() * 1.5; // random fall speed
this.size = Math.random() * 2;
this.alpha = Math.random() * 0.5;
}
}

Try It Yourself

chrono5.png

Follow these steps to run ChronosoPHIa on your own machine:


  1. Download or copy the ChronosoPHIa.html file from the attachment.
  2. Open the file in any modern web browser. No internet connection required after the first load (Google Fonts are optional, the page degrades gracefully without them).
  3. Enter your birth date in the left input field labeled 'Birth'.
  4. Watch the interface populate: your days lived appear in the PAST zone, the arc fills in the PRESENT zone, and your years remaining show in the FUTURE zone.
  5. If you are past 61.8% of your estimated lifespan (50.4 years for an 80-year expectancy), the Golden Era mode activates automatically with a 2-second color transition.
  6. Enter a personal deadline in the right input, a project, an event, a goal that matters to you.
  7. Watch the PROJECT zone display your live countdown in days, hours, minutes, and seconds. Let the sand particles falling in the background remind you that this time is real.


Privacy note: no data is ever sent to any server. Your birth date and deadline exist only in your browser tab. Close the tab and they are gone.

What Changed For Me

Building ChronosoPHIa did not cure my chronophobia. Time still passes. Deadlines still arrive. Years still accelerate. But something genuinely shifted in how I relate to that reality.

Seeing 18,000+ days lived, not as years of age, but as a raw count of days, is confrontational in the best way. It makes the past concrete and heavy with meaning. Those days happened. They cannot be unlived. But they also cannot be taken back.

The Golden Era threshold was personally significant. Crossing 61.8% did not feel like decline. It felt like a structural milestone, the moment when the ratio of past to future becomes golden. I responded by committing to finish what I start: less procrastination, more useful projects, more deliberate use of the remaining 38.2%.

The sand particles helped too. There is something meditative about watching them fall continuously. They do not accelerate or slow down. They do not judge. They simply fall, grain by grain, as time does.

ChronosoPHIa is not a productivity tool. It does not give you more time. It gives you a different way of seeing the time you have, structured, proportionate, and in its own way, beautiful.

If ChronosoPHIa resonates with you, if you also feel the weight of time passing and want to find structure in it, I encourage you to open the file, enter your date, and sit with what you see for a few minutes. The number of days you have lived is not a number to fear. It is a number to own.


φ = 1.61803398875…
From Chronophobia to ChronosoPHIa: a journey from anxiety to wisdom.


Thank you !

The Full Code

<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<title>ChronosoPHIa — From Chronophobia to Wisdom · φ</title>
<link href="https://fonts.googleapis.com/css2?family=Cormorant+Garamond:ital,wght@0,300;0,400;1,300&family=Share+Tech+Mono&family=Cinzel:wght@400;700&display=swap" rel="stylesheet">
<style>
:root {
--phi: 1.61803398875;
--bg: #0a0a0f;
--gold: #c8a96e;
--gold-dim: #5a4a3a;
--gold-bright: #f0e0b0;
--border: #2e2e3e;
--w: 480px; --h: 720px;
--transition-speed: 2s;
}

/* PURE GOLD MODE (Activated after 61.8%) */
.golden-era {
--bg: #1a160a;
--gold-dim: #8a6f3e;
--gold: #e8c97e;
--border: #c8a96e;
--gold-bright: #ffffff;
}

body { background: #050508; display: flex; flex-direction: column; align-items: center; padding: 40px; color: white; font-family: 'Share Tech Mono'; overflow-x: hidden;}

.device {
position: relative; width: var(--w); height: var(--h);
background: var(--bg); border: 1px solid var(--border);
border-radius: 15px; overflow: hidden;
box-shadow: 0 0 50px rgba(200, 169, 110, 0.1);
transition: all var(--transition-speed) ease-in-out;
}

/* Sand particle canvas */
#sand-canvas {
position: absolute; top: 0; left: 0; width: 100%; height: 100%;
pointer-events: none; z-index: 10;
}

.zone { position: absolute; width: 100%; display: flex; flex-direction: column; align-items: center; justify-content: center; border-bottom: 1px solid rgba(200, 169, 110, 0.1); z-index: 5; }
.zone-past { top: 0; height: 295px; }
.zone-present { top: 295px; height: 183px; }
.zone-future { top: 478px; height: 113px; }
.zone-project { bottom: 0; height: 129px; background: rgba(15,15,21,0.5); }

.label { font-family: 'Cinzel'; font-size: 10px; letter-spacing: 3px; color: var(--gold-dim); margin-bottom: 10px; transition: color var(--transition-speed); }
.value-big { font-family: 'Cormorant Garamond'; font-size: 90px; color: var(--gold-bright); line-height: 1; transition: color var(--transition-speed); }
.arc-container { position: relative; width: 300px; height: 130px; }
#phi-marker { position: absolute; font-family: 'Cormorant Garamond'; font-style: italic; font-size: 24px; color: var(--gold); opacity: 0.8; }

.config { width: var(--w); margin-top: 25px; display: grid; grid-template-columns: 1fr 1fr; gap: 20px; z-index: 20; }
.page-header {
text-align: center;
margin-bottom: 24px;
}
.page-title {
font-family: 'Cinzel', serif;
font-size: 28px;
letter-spacing: 8px;
color: #c8a96e;
text-shadow: 0 0 40px rgba(200,169,110,0.4);
}
.page-subtitle {
font-family: 'Cormorant Garamond', serif;
font-style: italic;
font-size: 13px;
color: #5a4a3a;
letter-spacing: 1px;
margin-top: 6px;
}
.config-labels {
width: 480px;
display: flex;
justify-content: space-around;
font-family: 'Cinzel', serif;
font-size: 9px;
letter-spacing: 3px;
color: #5a4a3a;
margin-bottom: 6px;
}
.footer-phi {
margin-top: 24px;
text-align: center;
max-width: 480px;
display: flex;
flex-direction: column;
gap: 10px;
}
.footer-line {
font-family: 'Cormorant Garamond', serif;
font-style: italic;
font-size: 13px;
color: #5a4a3a;
line-height: 1.6;
}
.footer-phi-symbol {
font-family: 'Share Tech Mono', monospace;
font-size: 10px;
color: #3a3028;
letter-spacing: 3px;
}

input[type="date"] { background: #161625; border: 1px solid var(--gold-dim); color: var(--gold-bright); padding: 12px; font-family: 'Share Tech Mono'; color-scheme: dark; width: 100%;}
</style>
</head>
<body>

<div class="page-header">
<div class="page-title">ChronosoPHIa</div>
<div class="page-subtitle">From Chronophobia to ChronosoPHIa&ensp;·&ensp;a journey from anxiety to wisdom</div>
</div>
<div class="device" id="main-device">
<canvas id="sand-canvas"></canvas>

<div class="zone zone-past">
<div class="label">Accumulated Experience</div>
<div class="value-big" id="days-lived">--</div>
<div id="msg-wisdom" style="font-family:'Cormorant Garamond'; font-style:italic; color:var(--gold-dim); text-align:center; padding:0 20px; font-size:13px; line-height:1.6;">Wisdom in the making...</div>
<div id="msg-sub" style="font-family:'Cinzel'; font-size:8px; letter-spacing:2px; color:var(--gold-dim); opacity:0.5; margin-top:6px; text-align:center; padding:0 30px; transition:opacity 2s;">FACING THE FEAR OF TIME · THROUGH φ</div>
</div>

<div class="zone zone-present">
<div class="label">Harmony (φ)</div>
<div class="arc-container">
<div id="phi-marker">φ</div>
<svg width="300" height="150">
<path d="M 40 120 A 110 110 0 0 1 260 120" fill="none" stroke="#1a1a2a" stroke-width="6"/>
<path id="life-arc" d="M 40 120 A 110 110 0 0 1 260 120" fill="none" stroke="var(--gold)" stroke-width="6" stroke-dasharray="345" stroke-dashoffset="345"/>
</svg>
<div style="position: absolute; bottom: 10px; left: 50%; transform: translateX(-50%); font-size: 28px; font-family: 'Cormorant Garamond'; color: var(--gold);">
<span id="percent">0</span>%
</div>
</div>
</div>

<div class="zone zone-future">
<div class="label">Golden Potential</div>
<div id="years-left" style="font-family: 'Cormorant Garamond'; font-size: 40px; color: var(--gold-bright);">--.-</div>
<div id="days-left-sub" style="font-size: 10px; color: var(--gold-dim);">YEARS TO INVEST</div>
</div>

<div class="zone zone-project">
<div class="label">Target Action</div>
<div id="project-timer" style="font-size: 24px; color: var(--gold-bright);">00J 00:00:00</div>
</div>
</div>

<div class="config-labels"><span>Birth</span><span>Deadline</span></div>
<div class="config">
<div class="input-box"><input type="date" id="birthInput"></div>
<div class="input-box"><input type="date" id="deadInput"></div>
</div>

<script>
const EXPECTANCY = 80;
const PHI_RATIO = 0.618033;
const canvas = document.getElementById('sand-canvas');
const ctx = canvas.getContext('2d');
// Redimensionner le canvas
canvas.width = 480;
canvas.height = 720;

let particles = [];

class Particle {
constructor() {
this.reset();
}
reset() {
this.x = Math.random() * canvas.width;
this.y = Math.random() * -canvas.height;
this.vy = 0.5 + Math.random() * 1.5;
this.size = Math.random() * 2;
this.alpha = Math.random() * 0.5;
}
update() {
this.y += this.vy;
if (this.y > canvas.height) this.reset();
}
draw() {
ctx.fillStyle = `rgba(200, 169, 110, ${this.alpha})`;
ctx.fillRect(this.x, this.y, this.size, this.size);
}
}

function initParticles() {
for (let i = 0; i < 100; i++) particles.push(new Particle());
}

function animateParticles() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
particles.forEach(p => { p.update(); p.draw(); });
requestAnimationFrame(animateParticles);
}

function update() {
const bVal = document.getElementById('birthInput').value;
const dVal = document.getElementById('deadInput').value;
const now = new Date();

if(bVal) {
const birth = new Date(bVal);
const livedMs = now - birth;
const livedDays = Math.floor(livedMs / 86400000);
const age = livedDays / 365.25;
const p = Math.min((age / EXPECTANCY) * 100, 100);

// --- LOGIQUE GOLDEN ERA ---
if (p >= 61.8) {
document.getElementById('main-device').classList.add('golden-era');
document.getElementById('msg-wisdom').innerText = "Welcome to your Golden Age.";
document.getElementById('msg-sub').style.opacity = "0";
} else {
document.getElementById('main-device').classList.remove('golden-era');
}

document.getElementById('days-lived').innerText = livedDays.toLocaleString('fr-FR');
document.getElementById('percent').innerText = p.toFixed(1);
document.getElementById('life-arc').style.strokeDashoffset = 345 - (345 * (p/100));

const angle = Math.PI * (1 - PHI_RATIO);
const px = 150 + 110 * Math.cos(angle);
const py = 120 - 110 * Math.sin(angle);
const marker = document.getElementById('phi-marker');
marker.style.left = (px - 10) + 'px';
marker.style.top = (py - 20) + 'px';

const left = Math.max(0, EXPECTANCY - age);
document.getElementById('years-left').innerText = left.toFixed(1);
}

if(dVal) {
const dead = new Date(dVal);
const diff = dead - now;
if(diff > 0) {
const dj = Math.floor(diff / 86400000);
const dh = Math.floor((diff % 86400000) / 3600000).toString().padStart(2,'0');
const dm = Math.floor((diff % 3600000) / 60000).toString().padStart(2,'0');
const ds = Math.floor((diff % 60000) / 1000).toString().padStart(2,'0');
document.getElementById('project-timer').innerText = dj + "J " + dh + ":" + dm + ":" + ds;
}
}
}

initParticles();
animateParticles();
setInterval(update, 1000);
document.getElementById('birthInput').addEventListener('input', update);
document.getElementById('deadInput').addEventListener('input', update);
</script>
<div class="footer-phi">
<span class="footer-line">"Facing the fear of time not by running away, but by organizing it through the Golden Ratio."</span>
<span class="footer-phi-symbol">φ = 1.61803398875…</span>
</div>
</body>
</html>

The C.Y.D : Code CYD (ESP32-2432S028R)

CYD.jpg

I did a light version of the HTML code on a Cheap Yellow Display. Full code here for makers who want to go deeper.

You just need to enter your birthday , the event or deadline , and internet connexion. It was just a test for me, so feel free to try it too , to improve it ...



#include <Arduino.h>
#include <TFT_eSPI.h>
#include <XPT2046_Touchscreen.h>
#include <SPI.h>
#include <WiFi.h>
#include <time.h>
#include <Preferences.h>

// --- MATERIEL CYD (ESP32-2432S028R) ---
#define T_CS 33
#define T_IRQ 36
TFT_eSPI tft = TFT_eSPI();
SPIClass hspi(HSPI);
XPT2046_Touchscreen ts(T_CS, T_IRQ);

const char* WIFI_SSID = "Your_SSID";
const char* WIFI_PASSWORD = "Your_Password";
const float LIFE_EXP = 80.0f;
const float PHI_R = 0.618033f;

uint16_t C_BG, C_GOLD, C_GOLD_DIM, C_BORDER, C_RED, C_WHITE;

// Layout Portrait 240x320
const int Z1_Y=0, Z1_H=90;
const int Z2_Y=90, Z2_H=115; // Zone Arc
const int Z3_Y=205, Z3_H=50;
const int Z4_Y=255, Z4_H=65;

struct ChronoData {
int bDay=00, bMonth=0, bYear=0000; // enter your Birthday here
int dDay=00, dMonth=0, dYear=0000; // enter event or deadline here
long daysLived=0;
float pctLife=0;
float yearsRemaining=0;
long deadlineSecs=0;
bool ntpSynced=false;
} cd;

uint32_t lastSecUpdate=0;
uint32_t lastTouch=0;

// ===========================================================
// UTILS (Placés en haut pour éviter l'erreur de Scope)
// ===========================================================
long daysBetween(int d1, int m1, int y1, int d2, int m2, int y2) {
struct tm t1 = {0}, t2 = {0};
t1.tm_mday = d1; t1.tm_mon = m1 - 1; t1.tm_year = y1 - 1900;
t2.tm_mday = d2; t2.tm_mon = m2 - 1; t2.tm_year = y2 - 1900;
time_t time1 = mktime(&t1);
time_t time2 = mktime(&t2);
return (long)(difftime(time2, time1) / 86400);
}

void calcData() {
struct tm now;
if(!getLocalTime(&now)) return;
cd.daysLived = daysBetween(cd.bDay, cd.bMonth, cd.bYear, now.tm_mday, now.tm_mon+1, now.tm_year+1900);
float age = cd.daysLived / 365.25f;
cd.pctLife = constrain((age / LIFE_EXP) * 100.0f, 0.0f, 100.0f);
cd.yearsRemaining = max(0.0f, LIFE_EXP - age);

struct tm dl = {0};
dl.tm_mday = cd.dDay; dl.tm_mon = cd.dMonth - 1; dl.tm_year = cd.dYear - 1900;
cd.deadlineSecs = max(0L, (long)(mktime(&dl) - time(nullptr)));
}

// ===========================================================
// DESSIN DES ZONES
// ===========================================================

void drawZone1() {
tft.fillRect(0, Z1_Y, 240, Z1_H, C_BG);
tft.setTextDatum(MC_DATUM);
tft.setTextColor(C_GOLD_DIM);
tft.drawString("ACCUMULATED EXPERIENCE", 120, Z1_Y + 20, 2);
tft.setTextColor(C_GOLD);
char buf[20]; sprintf(buf, "%ld DAYS", cd.daysLived);
tft.drawString(buf, 120, Z1_Y + 50, 4);
}

void drawZone2() {
tft.fillRect(0, Z2_Y, 240, Z2_H, C_BG);
// cy descendu à 105 pour laisser de la place au texte en haut
const int cx = 120, cy = Z2_Y + 105, r = 70;
tft.setTextDatum(MC_DATUM);
tft.setTextColor(C_GOLD_DIM);
tft.drawString("LIFE CYCLE (PHI)", 120, Z2_Y + 12, 2);

// Fond Arc
for(float a = PI; a <= 2*PI; a += 0.04) {
tft.drawLine(cx+r*cos(a), cy+r*sin(a), cx+(r+6)*cos(a), cy+(r+6)*sin(a), C_BORDER);
}
// Arc de Vie
float endA = PI + (cd.pctLife/100.0f)*PI;
for(float a = PI; a <= endA; a += 0.02) {
uint16_t col = ( (a-PI)/PI > PHI_R ) ? C_GOLD : tft.color565(120,100,60);
tft.drawLine(cx+r*cos(a), cy+r*sin(a), cx+(r+6)*cos(a), cy+(r+6)*sin(a), col);
}

// Marqueur PHI
float phiA = PI + PHI_R*PI;
tft.drawLine(cx+(r-4)*cos(phiA), cy+(r-4)*sin(phiA), cx+(r+10)*cos(phiA), cy+(r+10)*sin(phiA), C_WHITE);
tft.setTextColor(C_WHITE);
char ps[10]; sprintf(ps, "%.1f%%", cd.pctLife);
tft.drawString(ps, cx, cy - 30, 4);
}

void drawZone3() {
tft.fillRect(0, Z3_Y, 240, Z3_H, C_BG);
tft.setTextDatum(MC_DATUM);
tft.setTextColor(C_RED);
char ys[24]; sprintf(ys, "%.1f YEARS LEFT", cd.yearsRemaining);
tft.drawString(ys, 120, Z3_Y + 25, 4);
}

void drawZone5() {
tft.fillRect(0, Z4_Y, 240, Z4_H, C_BG);
tft.drawFastHLine(0, Z4_Y, 240, C_BORDER);
long s = cd.deadlineSecs;
tft.setTextDatum(MC_DATUM);
if (s <= 0) {
tft.setTextColor(C_GOLD);
tft.drawString("TARGET REACHED", 120, Z4_Y + 32, 4);
} else {
long d=s/86400, h=(s%86400)/3600, m=(s%3600)/60, sc=s%60;
char buf[24]; sprintf(buf, "%ldD %02ld:%02ld:%02ld", d, h, m, sc);
tft.setTextColor(C_WHITE);
tft.drawString(buf, 120, Z4_Y + 40, 4);
tft.setTextColor(C_GOLD_DIM);
tft.drawString("PROJECT DEADLINE", 120, Z4_Y + 12, 2);
}
}

// ===========================================================
// SETUP & LOOP
// ===========================================================

void setup() {
Serial.begin(115200);
tft.init(); tft.setRotation(0);
C_BG=TFT_BLACK; C_GOLD=tft.color565(200,169,110); C_GOLD_DIM=tft.color565(90,80,50);
C_BORDER=tft.color565(40,40,45); C_RED=tft.color565(200,50,50); C_WHITE=TFT_WHITE;
tft.fillScreen(C_BG);
hspi.begin(25, 39, 32, T_CS);
ts.begin(hspi); ts.setRotation(0);

WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
while(WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
configTime(3600, 3600, "pool.ntp.org");
struct tm ti;
while(!getLocalTime(&ti)) delay(500);
calcData();
drawZone1(); drawZone2(); drawZone3(); drawZone5();
}

void loop() {
// Touch Feedback
if (ts.touched()) {
uint32_t now = millis();
if (now - lastTouch > 800) {
lastTouch = now;
tft.fillCircle(230, 10, 4, C_GOLD);
delay(80);
tft.fillCircle(230, 10, 4, C_BG);
}
}

// Refresh Timer & Data
if (millis() - lastSecUpdate > 1000) {
lastSecUpdate = millis();
calcData();
drawZone5();
// Refresh complet périodique
static int refreshCounter = 0;
if (++refreshCounter > 300) { // 5 minutes
drawZone1(); drawZone2(); drawZone3();
refreshCounter = 0;
}
}
}