Typography and Text Effects

Poetry Grid Layout for Mountain Poems

Complete poetry grid typesetting in a mountain poetry collection scenario: includes real content, interactive controls, clear status feedback, and responsive layouts.

Typography and Text EffectsPoetry grid typographyHTMLCSS GridResponsive Design
With JavaScript enabled, you can edit, run, and save this example. The fixed source is as follows:
<!doctype html>
<html lang="en" dir="ltr">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Poetry Grid Layout for Mountain Poems</title>
  <style>
    :root { --ink:#ecf7f3; --paper:#071310; --accent:#c66a2d; --secondary:#b5c88d; --line:color-mix(in srgb, var(--ink) 18%, transparent); --shadow:0 24px 60px color-mix(in srgb, var(--ink) 16%, transparent); color-scheme:light; }
    * { box-sizing:border-box; }
    html { min-width:320px; background:var(--paper); }
    body { min-height:100vh; margin:0; overflow-x:hidden; color:var(--ink); font-family:ui-monospace,"SFMono-Regular",Consolas,monospace; background:linear-gradient(color-mix(in srgb,var(--secondary) 5%,transparent) 1px,transparent 1px),linear-gradient(90deg,color-mix(in srgb,var(--secondary) 5%,transparent) 1px,transparent 1px),var(--paper);background-size:24px 24px; }
    button,input,select,textarea { color:inherit; font:inherit; }
    button,[role="button"],input,select,textarea { accent-color:var(--accent); }
    button { cursor:pointer; }
    button:focus-visible,input:focus-visible,select:focus-visible,textarea:focus-visible,[tabindex]:focus-visible { outline:3px solid var(--accent); outline-offset:3px; }
    [hidden] { display:none !important; }
    @media (max-width:700px) { .mast h1 { line-height:1.08 !important; letter-spacing:-.035em !important; overflow-wrap:anywhere; } }
    @media (prefers-reduced-motion:reduce) { *,*::before,*::after { scroll-behavior:auto !important; animation-duration:.01ms !important; animation-iteration-count:1 !important; transition-duration:.01ms !important; } }
    .page{width:min(1080px,calc(100% - 30px));margin:auto;padding:48px 0}.eyebrow{color:var(--secondary);font:700 12px/1.3 ui-monospace,monospace}.eyebrow::before{content:"> ";color:var(--accent)}.mast{display:grid;grid-template-columns:1fr auto;border:1px solid var(--secondary);padding:18px;gap:24px;align-items:center;margin-bottom:16px}.mast h1{font-family:ui-monospace,"SFMono-Regular",monospace;font-weight:700;font-size:clamp(34px,7vw,72px);letter-spacing:-.055em;margin:12px 0;line-height:1.05}.intro{margin:0;color:color-mix(in srgb,var(--ink) 72%,transparent);font:400 14px/1.7 ui-monospace,monospace}.scenario{padding:7px 10px;border:1px dashed var(--secondary);font:700 11px/1 ui-monospace,monospace}.demo{border-color:var(--secondary);border-radius:8px;box-shadow:0 0 50px color-mix(in srgb,var(--secondary) 15%,transparent);position:relative;min-height:390px;padding:26px;background:color-mix(in srgb,var(--paper) 94%,#000)}@media(max-width:700px){.page{width:calc(100% - 18px);padding:20px 0}.mast{grid-template-columns:1fr}.demo{padding:14px}}
    .panel{padding:26px;border:1px solid var(--line);border-radius:2px;background:var(--paper)}.stack{display:grid;gap:28px}.row{display:flex;gap:20px;flex-wrap:wrap}.action{padding:9px 2px;border:0;border-bottom:2px solid var(--line);background:transparent}.action.primary,.action.is-active{border-color:var(--accent);color:var(--accent)}.muted{font-size:14px;line-height:1.9}.status{min-height:20px;margin-top:28px;font-size:13px}.metric{font-size:clamp(40px,9vw,88px);font-weight:500;letter-spacing:-.06em}.meter{height:2px;background:var(--line)}.meter>i{display:block;height:100%;background:var(--accent)}.chip{font-size:11px;letter-spacing:.12em;text-transform:uppercase}
    .composition-split{display:grid;grid-template-columns:150px minmax(0,1fr);gap:18px;align-items:start}.split-note{position:sticky;top:20px;display:grid;gap:14px;padding:18px 12px;border-block:3px double var(--accent);font-size:13px;line-height:1.65}.split-note b{font:900 12px/1 ui-monospace,monospace;letter-spacing:.12em}.split-note span{writing-mode:vertical-rl;min-height:120px;color:color-mix(in srgb,var(--ink) 60%,transparent)}.composition-split .demo{min-width:0}@media(max-width:900px){.composition-split{grid-template-columns:1fr}.split-note{position:static;grid-template-columns:auto 1fr}.split-note span{writing-mode:horizontal-tb;min-height:0}}
    .poem-grid-lab{display:grid;gap:18px;min-width:0}.poem-controls{display:grid;grid-template-columns:minmax(0,1fr) auto minmax(190px,.6fr);gap:18px;align-items:end}.poem-controls>*{min-width:0}.poem-controls h2{margin:.3em 0 0}.poem-controls label{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:8px;font-weight:800}.poem-controls input{grid-column:1/-1;min-width:0}.poem-figure{--poem-gap:24px;display:grid;min-width:0;min-height:410px;padding:clamp(28px,7vw,80px);border:1px solid var(--line);background:var(--paper)}.poem-figure figcaption{color:var(--accent);font:800 11px/1 ui-monospace,monospace;letter-spacing:.18em}.poem-figure blockquote{display:grid;align-self:center;gap:var(--poem-gap);min-width:0;margin:0}.poem-figure p{margin:0;font-family:ui-serif,Georgia,serif;font-size:clamp(22px,4vw,44px);line-height:1.25}.poem-figure.is-stair p:nth-child(2){margin-left:10%}.poem-figure.is-stair p:nth-child(3){margin-left:20%}.poem-figure.is-stair p:nth-child(4){margin-left:30%}.poem-figure.is-columns blockquote{grid-template-columns:repeat(2,minmax(0,1fr))}.poem-figure.is-center blockquote{text-align:center}@media(max-width:900px){.poem-controls{grid-template-columns:1fr}.poem-figure.is-columns blockquote{grid-template-columns:1fr}.poem-figure.is-stair p:nth-child(n){margin-left:0}}.workflow-dispatch{display:grid;grid-template-columns:minmax(210px,.48fr) minmax(0,1.52fr);gap:18px}.dispatch-console{display:grid;align-content:start;gap:16px;padding:22px;border:1px solid var(--line);border-radius:18px;background:color-mix(in srgb,var(--secondary) 12%,var(--paper))}.dispatch-console h2{margin:.2em 0}.dispatch-console form,.dispatch-console label{display:grid;gap:7px}.dispatch-console input,.dispatch-console select{min-width:0;width:100%;padding:10px;border:1px solid var(--line);border-radius:8px;background:var(--paper)}.dispatch-console fieldset{display:flex;gap:12px;border:1px solid var(--line);border-radius:10px}.dispatch-console fieldset label{display:flex;align-items:center}.dispatch-workbench{--dispatch-load:.22;min-width:0;padding:14px;border-left:8px solid color-mix(in srgb,var(--accent) calc(var(--dispatch-load)*100%),var(--line));background:linear-gradient(90deg,color-mix(in srgb,var(--accent) 8%,transparent),transparent 28%)}.dispatch-workbench[data-dispatch-priority="urgent"]{box-shadow:inset 0 0 0 2px var(--accent)}@media(max-width:900px){.workflow-dispatch{grid-template-columns:1fr}.dispatch-console{order:2}}
  </style>
</head>
<body data-aesthetic="terminal" data-composition="split-note">
  <main class="page">
    <header class="mast"><div><span class="eyebrow">terminal / Poetry Grid Layout / ADVANCED</span><h1>Poetry Grid Layout for Mountain Poems</h1><p class="intro">Complete poetry grid typesetting in a mountain poetry collection scenario: includes real content, interactive controls, clear status feedback, and responsive layouts.</p></div><span class="scenario">Mountain Poetry Collection</span></header>
    <div class="composition-split"><aside class="split-note"><b>CASE 02</b><span>Master the semantic structure, responsive composition, keyboard operation, and state synchronization of poetic grid typography.</span></aside><section class="demo" aria-label="Poetry Grid Layout Interactive Area for Mountain Anthology"><div class="workflow-dispatch"><aside class="dispatch-console"><span class="eyebrow">Mountain Poems DISPATCH</span><h2>Poem Manuscript Editing Console</h2><form id="workflowDispatchForm"><label>Task Type<select id="workflowDispatchKind"><option>Mountain Path</option><option>Valley Chapter</option><option>Night Stay</option></select></label><label>Number of lines<input id="workflowDispatchAmount" type="number" min="1" max="9999" value="42"><span>Row</span></label><fieldset><legend>Processing priority</legend><label><input type="radio" name="workflowPriority" value="normal" checked>Regular</label><label><input type="radio" name="workflowPriority" value="urgent">Urgent</label></fieldset><button class="action primary" type="submit">Add to Poetry Collection</button></form><label>Current task<select id="workflowDispatchActive" aria-label="Switch current task"><option value="1">Mountain Path</option><option value="2">Valley Chapter</option></select></label><output id="workflowDispatchSummary">Waiting for Dispatch</output></aside><section id="workflowCore" class="workflow-core dispatch-workbench" data-dispatch-priority="normal"><!-- 11DZ_CORE_START:typography-text-poem-grid --><div class="poem-grid-lab"><header class="poem-controls panel"><div><span class="eyebrow">POEM GRID</span><h2>Poetry grid typography</h2></div><div class="row" role="group" aria-label="Poem layout"><button class="action poem-layout is-active" type="button" data-poem-layout="stair" aria-pressed="true">Steps</button><button class="action poem-layout" type="button" data-poem-layout="columns" aria-pressed="false">Two-column</button><button class="action poem-layout" type="button" data-poem-layout="center" aria-pressed="false">Centered</button></div><label>Poem line spacing <input id="poemGap" type="range" min="8" max="48" value="24" data-core-bridge="typography-text-poem-grid"><output id="poemGapValue">24px</output></label></header><figure id="poemFigure" class="poem-figure is-stair"><figcaption>Poems of the Hills · Four-Line Verse</figcaption><blockquote><p>Light falls on an unnamed road</p><p>The wind folds the distance into the page</p><p>We walked along the quiet whitespace</p><p>Read, and today slowly glows</p></blockquote></figure></div><!-- 11DZ_CORE_END --></section></div><p id="status" class="status" role="status" aria-live="polite"></p></section></div>
  </main>
  <script>
    'use strict';
    const statusOutput = document.querySelector('#status');
    const announce = message => { statusOutput.textContent = message; };
    /* 11DZ_CORE_SCRIPT_START:typography-text-poem-grid */
const poemFigure=document.querySelector('#poemFigure');const poemGap=document.querySelector('#poemGap');document.querySelectorAll('.poem-layout').forEach(button=>button.addEventListener('click',()=>{poemFigure.className='poem-figure is-'+button.dataset.poemLayout;document.querySelectorAll('.poem-layout').forEach(item=>{const selected=item===button;item.classList.toggle('is-active',selected);item.setAttribute('aria-pressed',String(selected));});announce('Poetry has been switched to'+button.textContent+'Layout');}));poemGap.addEventListener('input',()=>{poemFigure.style.setProperty('--poem-gap',poemGap.value+'px');document.querySelector('#poemGapValue').textContent=poemGap.value+'px';announce('Poem line spacing '+poemGap.value+' pixels');});
/* 11DZ_CORE_SCRIPT_END */
const workflowBridgeSpec={"name":"typography-text-poem-grid","selector":"[data-core-bridge=\"typography-text-poem-grid\"]","mode":"range","key":"ArrowRight"};const workflowBridgeCore=document.querySelector('#workflowCore');const workflowBridgeControl=workflowBridgeCore.querySelector(workflowBridgeSpec.selector);if(!workflowBridgeControl)throw new Error('Missing core bridge: '+workflowBridgeSpec.name);const workflowBridgeControlledId=workflowBridgeControl.getAttribute('aria-controls');const workflowBridgeControlled=workflowBridgeControlledId?document.getElementById(workflowBridgeControlledId):null;workflowBridgeCore.dataset.workflowBridge=workflowBridgeSpec.name;workflowBridgeCore.dataset.workflowVersion='0';function workflowBridgeSerialize(){const visualNode=workflowBridgeCore.firstElementChild||workflowBridgeCore;const visual=getComputedStyle(visualNode);const outputs=[...workflowBridgeCore.querySelectorAll('output,[role="status"],[aria-live],meter,progress')].map(node=>node.textContent.trim()+'|'+node.getAttribute('aria-valuenow')+'|'+node.getAttribute('value'));const canvas=[...workflowBridgeCore.querySelectorAll('canvas')].map(node=>{try{return node.toDataURL().slice(-160);}catch{return 'canvas-unavailable';}});return JSON.stringify({html:workflowBridgeCore.innerHTML,status:statusOutput.textContent,outputs,canvas,visual:[visual.display,visual.visibility,visual.opacity,visual.transform,visual.filter,visual.backgroundColor,visual.width,visual.height],scroll:workflowBridgeSpec.mode==='scroll'?workflowBridgeControl.scrollTop:null});}let workflowBridgeLastEffect=workflowBridgeSerialize();function workflowBridgeSummary(){const label=(workflowBridgeControl.getAttribute('aria-label')||workflowBridgeControl.textContent||workflowBridgeControl.value||workflowBridgeSpec.name).trim().replace(/\s+/g,' ').slice(0,72);return label+' · Core Version '+workflowBridgeCore.dataset.workflowVersion;}function workflowBridgeCommit(){const effect=workflowBridgeSerialize();if(effect===workflowBridgeLastEffect)return {changed:false,summary:workflowBridgeSummary()};workflowBridgeLastEffect=effect;workflowBridgeCore.dataset.workflowVersion=String(Number(workflowBridgeCore.dataset.workflowVersion||0)+1);return {changed:true,summary:workflowBridgeSummary()};}function workflowBridgeScheduleCommit(){queueMicrotask(workflowBridgeCommit);setTimeout(workflowBridgeCommit,0);}workflowBridgeControl.addEventListener("input",workflowBridgeScheduleCommit);workflowBridgeControl.addEventListener('change',workflowBridgeScheduleCommit);const workflowBridgeStateTargets=new Set(workflowBridgeCore.querySelectorAll('dialog'));if(workflowBridgeControlled&&workflowBridgeCore.contains(workflowBridgeControlled))workflowBridgeStateTargets.add(workflowBridgeControlled);workflowBridgeStateTargets.forEach(target=>['close','cancel','toggle'].forEach(eventName=>target.addEventListener(eventName,workflowBridgeScheduleCommit)));function workflowBridgeActivate(){workflowBridgeControl.focus();const step=Number(workflowBridgeControl.step)||1;const min=workflowBridgeControl.min===''?-Infinity:Number(workflowBridgeControl.min);const max=workflowBridgeControl.max===''?Infinity:Number(workflowBridgeControl.max);let next=Math.min(max,Math.max(min,(Number(workflowBridgeControl.value)||0)+step));if(next===Number(workflowBridgeControl.value))next=Math.max(min,Number(workflowBridgeControl.value)-step);workflowBridgeControl.value=String(next);workflowBridgeControl.dispatchEvent(new Event('input',{bubbles:true}));workflowBridgeControl.dispatchEvent(new Event('change',{bubbles:true}));const result=workflowBridgeCommit();setTimeout(workflowBridgeCommit,0);return result;}function workflowBridgeReset(){workflowBridgeCore.dataset.workflowVersion='0';workflowBridgeLastEffect=workflowBridgeSerialize();}
const workflowDispatchCore=document.querySelector('#workflowCore');const workflowDispatchForm=document.querySelector('#workflowDispatchForm');const workflowDispatchSelect=document.querySelector('#workflowDispatchActive');const workflowDispatchJobs=new Map([["1",{"label":"Mountain Path","amount":12,"priority":"normal","touches":0}],["2",{"label":"Valley Chapter","amount":21,"priority":"urgent","touches":0}]]);let workflowDispatchSerial=workflowDispatchJobs.size;function workflowDispatchDrive(job,activate=false){workflowDispatchCore.dataset.dispatchPriority=job.priority;workflowDispatchCore.style.setProperty('--dispatch-load',Math.min(.95,.16+job.amount/120));const bridge=activate?workflowBridgeActivate():{changed:false,summary:workflowBridgeSummary()};document.querySelector('#workflowDispatchSummary').textContent=job.label+' · '+job.amount+' Line · '+bridge.summary;announce('Poem Draft Typesetting Current Task:'+job.label);}function workflowDispatchRender(activeId,activate=false){workflowDispatchSelect.replaceChildren(...[...workflowDispatchJobs].map(([id,job])=>{const option=document.createElement('option');option.value=id;option.textContent=job.label+(job.priority==='urgent'?' · Urgent':'');return option;}));workflowDispatchSelect.value=activeId;workflowDispatchDrive(workflowDispatchJobs.get(activeId),activate);}workflowDispatchForm.addEventListener('submit',event=>{event.preventDefault();const data=new FormData(workflowDispatchForm);const id=String(++workflowDispatchSerial);workflowDispatchJobs.set(id,{label:document.querySelector('#workflowDispatchKind').value,amount:Math.max(1,Number(document.querySelector('#workflowDispatchAmount').value)||1),priority:data.get('workflowPriority'),touches:0});workflowDispatchRender(id,true);});workflowDispatchSelect.addEventListener('change',()=>workflowDispatchDrive(workflowDispatchJobs.get(workflowDispatchSelect.value),true));workflowDispatchCore.addEventListener('focusin',()=>{const job=workflowDispatchJobs.get(workflowDispatchSelect.value);if(!job)return;job.touches+=1;document.querySelector('#workflowDispatchSummary').textContent=job.label+' · '+job.amount+' Line · '+workflowBridgeSummary();});workflowDispatchRender('1',false);
workflowBridgeReset();
  </script>
</body>
</html>
Page feedbackFound an issue or have suggestions for improvement?
Feedback features need to be used in the online version

Please enable JavaScript in the online version before submitting; local features of the current tool or example are not affected.

Go to the online version for feedback