cellar-protocol/frost-calculator.html

408 lines
15 KiB
HTML
Raw Normal View History

2026-07-18 04:41:23 +02:00
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Frost-Depth Calculator | Barbara Cintron</title>
<style>
:root {
--midnight: #0c0f1a;
--plowsteel: #2d3a4f;
--wheatgold: #f4e8c8;
--loam: #8b7355;
--frostline: #e8f4ff;
--iceblue: #a8d5e8;
--deepfreeze: #1a2838;
}
html, body {
background: var(--midnight);
color: var(--frostline);
font-family: 'JetBrains Mono', 'IBM Plex Mono', monospace;
margin: 0;
padding: 0;
line-height: 1.6;
}
header {
background: linear-gradient(to bottom, var(--deepfreeze), var(--plowsteel));
padding: 2em;
border-bottom: 3px solid var(--wheatgold);
}
header h1 {
font-size: 1.8rem;
letter-spacing: 0.12em;
margin: 0;
color: var(--wheatgold);
}
header a {
color: var(--loam);
text-decoration: none;
font-size: 0.85rem;
letter-spacing: 0.08em;
}
main {
max-width: 80ch;
margin: 0 auto;
padding: 3em 2em;
}
.tool-container {
border: 2px solid var(--wheatgold);
padding: 2.5em;
margin: 2em 0;
background: rgba(45, 58, 79, 0.5);
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.4);
}
.tool-title {
font-size: 1.4rem;
color: var(--iceblue);
letter-spacing: 0.1em;
margin-bottom: 0.5em;
border-bottom: 1px solid var(--loam);
padding-bottom: 1em;
}
.tool-subtitle {
color: var(--loam);
font-size: 0.9rem;
letter-spacing: 0.05em;
margin-bottom: 2em;
}
.input-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
gap: 1.5em;
margin-bottom: 2em;
}
.input-group {
display: flex;
flex-direction: column;
gap: 0.5em;
}
.input-label {
color: var(--wheatgold);
font-size: 0.8rem;
letter-spacing: 0.08em;
}
.input-control {
background: var(--deepfreeze);
border: 1px solid var(--plowsteel);
color: var(--frostline);
padding: 0.75em;
font-family: inherit;
font-size: 1rem;
outline: none;
transition: border-color 0.3s ease;
}
.input-control:focus {
border-color: var(--iceblue);
}
.calc-button {
background: var(--loam);
color: var(--midnight);
border: none;
padding: 1em 2em;
font-family: inherit;
font-size: 1rem;
letter-spacing: 0.1em;
cursor: pointer;
margin: 1em 0;
transition: all 0.4s ease;
}
.calc-button:hover {
background: var(--wheatgold);
transform: translateY(-2px);
}
.result-panel {
margin-top: 2em;
padding: 2em;
border-left: 4px solid var(--iceblue);
background: rgba(168, 213, 232, 0.08);
display: none;
}
.result-label {
color: var(--loam);
font-size: 0.8rem;
letter-spacing: 0.08em;
margin-bottom: 0.5em;
}
.result-value {
font-size: 2.2rem;
color: var(--iceblue);
letter-spacing: 0.15em;
margin-bottom: 1em;
}
.result-unit {
color: var(--wheatgold);
font-size: 1.2rem;
}
.formula-box {
border: 1px dashed var(--plowsteel);
padding: 1.5em;
margin: 2em 0;
background: rgba(26, 40, 56, 0.6);
}
.formula-title {
color: var(--loam);
font-size: 0.8rem;
letter-spacing: 0.08em;
margin-bottom: 1em;
}
.equation {
font-size: 1.3rem;
color: var(--wheatgold);
letter-spacing: 0.12em;
text-align: center;
margin: 1em 0;
}
.variable-def {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
gap: 1em;
margin-top: 1.5em;
font-size: 0.9rem;
}
.var-item {
border-left: 2px solid var(--loam);
padding-left: 1em;
}
.var-symbol {
color: var(--iceblue);
font-weight: bold;
}
.citation-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 1em;
margin: 2em 0;
}
.citation-card {
border: 1px solid var(--plowsteel);
padding: 1em;
background: rgba(45, 58, 79, 0.3);
}
.citation-id {
color: var(--loam);
font-size: 0.75rem;
letter-spacing: 0.08em;
margin-bottom: 0.5em;
}
.citation-name {
color: var(--wheatgold);
font-size: 0.95rem;
letter-spacing: 0.05em;
}
.image-frame {
margin: 2em 0;
border: 2px solid var(--plowsteel);
padding: 0.5em;
}
.image-frame img {
width: 100%;
height: auto;
filter: sepia(0.2) contrast(1.1) brightness(0.9);
display: block;
}
.caption {
text-align: center;
font-size: 0.8rem;
color: var(--loam);
margin-top: 0.75em;
letter-spacing: 0.05em;
}
.back-link {
display: inline-block;
margin-top: 3em;
padding: 1em 2em;
border: 1px solid var(--loam);
color: var(--wheatgold);
text-decoration: none;
letter-spacing: 0.1em;
transition: all 0.4s ease;
}
.back-link:hover {
background: rgba(139, 115, 85, 0.15);
}
.moisture-slider {
-webkit-appearance: none;
width: 100%;
height: 6px;
background: var(--plowsteel);
outline: none;
margin: 1em 0;
}
.moisture-slider::-webkit-slider-thumb {
-webkit-appearance: none;
width: 20px;
height: 20px;
background: var(--iceblue);
cursor: pointer;
}
.moisture-display {
display: flex;
justify-content: space-between;
color: var(--iceblue);
font-size: 0.9rem;
}
</style>
</head>
<body>
<header>
<h1>FROST-DEPTH CALCULATOR</h1>
<a href="/">← RETURN TO HUB</a>
</header>
<main>
<div class="image-frame">
<img src="https://images.pexels.com/photos/21077867/pexels-photo-21077867.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=650&w=940"
alt="Snow-covered Iowa farmstead with barns and silos under winter sky" />
<div class="caption">Storm Lake county soil profile in midwinter. The white layer hides the depth we calculate.</div>
</div>
<div class="tool-container">
<div class="tool-title">STEFAN PHASE-CHANGE MODEL</div>
<div class="tool-subtitle">Predict maximum frost penetration from accumulated degree-days and soil moisture content</div>
<form id="frostForm">
<div class="input-grid">
<div class="input-group">
<label class="input-label" for="hddInput">ACCUMULATED HEATING DEGREE-DAYS (base 0°C)</label>
<input type="number" id="hddInput" class="input-control"
placeholder="e.g., 3200"
step="100" min="0" max="20000" required>
<small style="color: var(--loam); font-size: 0.75rem;">Typical Iowa January-March: 45006800</small>
</div>
<div class="input-group">
<label class="input-label" for="moistureSlider">SOIL MOISTURE CONTENT (% volumetric)</label>
<input type="range" id="moistureSlider" class="moisture-slider"
min="5" max="45" value="22" step="1">
<div class="moisture-display">
<span>Dry Sand (5%)</span>
<span id="moistureValue" style="color: var(--iceblue);">22%</span>
<span>Saturated Clay (45%)</span>
</div>
<small style="color: var(--loam); font-size: 0.75rem;">Storm Lake clay-loam average: 1826%</small>
</div>
</div>
<button type="submit" class="calc-button">COMPUTE FROST DEPTH</button>
</form>
<div id="resultPanel" class="result-panel">
<div class="result-label">PREDICTED MAXIMUM PENETRATION</div>
<div class="result-value"><span id="depthResult">0</span> <span class="result-unit">cm</span></div>
<div class="result-label">IMPERIAL EQUIVALENT</div>
<div class="result-value" style="font-size: 1.4rem;"><span id="inchResult">0</span> <span class="result-unit">inches</span></div>
<div class="result-label">AGRICULTURAL IMPLICATION</div>
<div id="implicationText" style="color: var(--frostline); font-size: 0.95rem; line-height: 1.8;"></div>
</div>
</div>
<div class="formula-box">
<div class="formula-title">UNDERLYING MATHEMATICS</div>
<div class="equation">D = K(m) × √(HDD)</div>
<div class="variable-def">
<div class="var-item">
<span class="var-symbol">D</span>: frost depth (cm)
</div>
<div class="var-item">
<span class="var-symbol">K(m)</span>: conductivity factor, moisture-dependent<br>
<small style="color: var(--loam);">K = 2.2 + 0.048m, where m ∈ [5, 45]</small>
</div>
<div class="var-item">
<span class="var-symbol">HDD</span>: heating degree-days (°C·days)<br>
<small style="color: var(--loam);">Σ(max(0, T_base T_daily))</small>
</div>
</div>
</div>
<div class="citation-grid">
<div class="citation-card">
<div class="citation-id">WIKIDATA Q14524610</div>
<div class="citation-name">Heating Degree Day</div>
<small style="color: var(--loam);">Sum of temperature deficits driving phase change</small>
</div>
<div class="citation-card">
<div class="citation-id">WIKIDATA Q3775789</div>
<div class="citation-name">Stefan Problem</div>
<small style="color: var(--loam);">Moving boundary solution for solidification fronts</small>
</div>
<div class="citation-card">
<div class="citation-id">WIKIDATA Q487005</div>
<div class="citation-name">Thermal Conductivity</div>
<small style="color: var(--loam);">Material property scaling heat flux through soil matrix</small>
</div>
</div>
<div style="margin: 2em 0; padding: 1.5em; border-left: 3px solid var(--iceblue); background: rgba(168, 213, 232, 0.05);">
<small style="color: var(--loam); letter-spacing: 0.08em; display: block; margin-bottom: 0.5em;">OPERATIONAL NOTES — STORM LAKE COUNTY</small>
<div style="color: var(--frostline); font-size: 0.95rem; line-height: 1.8;">
The clay-loam deposits beneath our office plaza retain moisture at 22% volumetric even in drought years.
When January brings 4200 HDD and February adds 2800 more, the root zone freezes to 112 centimeters—deeper
than the taproots of turnips left to survive the winter. This is why we dig the cellar to 1.8 meters. This
is why the water pipes run south of the frost line. This is why we teach children to measure before they build.
</div>
</div>
<a href="/" class="back-link">RETURN TO HUB</a>
</main>
<script>
const form = document.getElementById('frostForm');
const slider = document.getElementById('moistureSlider');
const moistureDisplay = document.getElementById('moistureValue');
const resultPanel = document.getElementById('resultPanel');
const depthResult = document.getElementById('depthResult');
const inchResult = document.getElementById('inchResult');
const implicationText = document.getElementById('implicationText');
// Update moisture display on slider drag
slider.addEventListener('input', function() {
moistureDisplay.textContent = this.value + '%';
});
// Compute K factor from moisture content
function computeK(moisturePercent) {
// Linear interpolation: dry sand (5%) → K=2.2, saturated clay (45%) → K=4.2
// K = 2.2 + (moisture - 5) × (2.0 / 40)
return 2.2 + (moisturePercent - 5) * (2.0 / 40);
}
// Main calculation
form.addEventListener('submit', function(e) {
e.preventDefault();
const hdd = parseFloat(document.getElementById('hddInput').value);
const moisture = parseFloat(slider.value);
if (isNaN(hdd) || hdd < 0) {
alert('Enter valid heating degree-days (≥ 0)');
return;
}
const K = computeK(moisture);
const depthCM = K * Math.sqrt(hdd);
const depthInches = depthCM / 2.54;
// Display results
depthResult.textContent = depthCM.toFixed(1);
inchResult.textContent = depthInches.toFixed(1);
// Generate agricultural implication
let implication = '';
if (depthCM < 30) {
implication = 'Light freeze. Surface crops protected by snow cover. Root cellars safe at 1.2m.';
} else if (depthCM < 60) {
implication = 'Moderate freeze. Perennials require mulch. Water lines must exceed 0.9m depth.';
} else if (depthCM < 120) {
implication = 'Deep freeze. Taproots of biennial vegetables enter dormancy. Foundation footings must exceed 1.5m.';
} else {
implication = 'Critical freeze. Full soil column compromised. All infrastructure requires heated trenches or geothermal displacement.';
}
implicationText.textContent = implication;
resultPanel.style.display = 'block';
});
</script>
</body>
</html>