fix: replace Inter with Space Grotesk (#audit-P3)
Inter was flagged as the only AI tell in the audit. Space Grotesk fits the pedal brand — mechanical, precise character with excellent small-screen readability. Changes: - src/index.css: body font-family Inter → Space Grotesk - src/App.jsx: Google Fonts import + body font-family + inline style - src/GlobalSettings.jsx, GlobalEQ.jsx, ModelBrowser.jsx, FocusView.jsx: inline fontFamily Inter → Space Grotesk - index.html: added Google Fonts preconnect + Space Grotesk import - docs/helix-stadium-mockup.html, docs/helix-stadium-concept.html: updated font imports and font-family
This commit is contained in:
@@ -5,7 +5,7 @@
|
|||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<title>NAM Pedal — Helix Stadium UX Concept</title>
|
<title>NAM Pedal — Helix Stadium UX Concept</title>
|
||||||
<style>
|
<style>
|
||||||
@import url('https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;700&family=Inter:wght@300;400;500;600;700&display=swap');
|
@import url('https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;700&family=Space+Grotesk:wght@300;400;500;600;700&display=swap');
|
||||||
|
|
||||||
* { box-sizing: border-box; margin: 0; padding: 0; user-select: none; -webkit-tap-highlight-color: transparent; }
|
* { box-sizing: border-box; margin: 0; padding: 0; user-select: none; -webkit-tap-highlight-color: transparent; }
|
||||||
|
|
||||||
@@ -29,7 +29,7 @@
|
|||||||
height: 100%;
|
height: 100%;
|
||||||
background: var(--bg);
|
background: var(--bg);
|
||||||
color: var(--text);
|
color: var(--text);
|
||||||
font-family: 'Inter', sans-serif;
|
font-family: 'Space Grotesk', sans-serif;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,10 +4,10 @@
|
|||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
|
||||||
<title>Pi Multi-FX — Helix Stadium Mockup</title>
|
<title>Pi Multi-FX — Helix Stadium Mockup</title>
|
||||||
<link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;700&family=Inter:wght@300;400;500;600;700&display=swap" rel="stylesheet">
|
<link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;700&family=Space+Grotesk:wght@300;400;500;600;700&display=swap" rel="stylesheet">
|
||||||
<style>
|
<style>
|
||||||
* { box-sizing: border-box; margin: 0; padding: 0; -webkit-tap-highlight-color: transparent; user-select: none; }
|
* { box-sizing: border-box; margin: 0; padding: 0; -webkit-tap-highlight-color: transparent; user-select: none; }
|
||||||
body { background: #0A0A0C; color: #F0EDE6; font-family: 'Inter', sans-serif; display: flex; justify-content: center; min-height: 100vh; }
|
body { background: #0A0A0C; color: #F0EDE6; font-family: 'Space Grotesk', sans-serif; display: flex; justify-content: center; min-height: 100vh; }
|
||||||
|
|
||||||
.device {
|
.device {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|||||||
+77
-12
@@ -139,10 +139,10 @@ function getBlockDisplayName(block) {
|
|||||||
|
|
||||||
// ── CSS ─────────────────────────────────────────────────────
|
// ── CSS ─────────────────────────────────────────────────────
|
||||||
const css = `
|
const css = `
|
||||||
@import url('https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;700&family=Inter:wght@300;400;500;600&display=swap');
|
@import url('https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;700&family=Space+Grotesk:wght@300;400;500;600&display=swap');
|
||||||
* { box-sizing: border-box; margin: 0; padding: 0; -webkit-tap-highlight-color: transparent; user-select: none; }
|
* { box-sizing: border-box; margin: 0; padding: 0; -webkit-tap-highlight-color: transparent; user-select: none; }
|
||||||
html, body { height: 100%; overflow: hidden; background: ${T.bg}; }
|
html, body { height: 100%; overflow: hidden; background: ${T.bg}; }
|
||||||
body { color: ${T.textPrimary}; font-family: 'Inter', sans-serif; }
|
body { color: ${T.textPrimary}; font-family: 'Space Grotesk', sans-serif; }
|
||||||
:root { --amber: ${T.amber}; --blue: ${T.blue}; --green: ${T.green}; }
|
:root { --amber: ${T.amber}; --blue: ${T.blue}; --green: ${T.green}; }
|
||||||
.mono { font-family: 'JetBrains Mono', monospace; }
|
.mono { font-family: 'JetBrains Mono', monospace; }
|
||||||
::-webkit-scrollbar { width: 4px; height: 4px; }
|
::-webkit-scrollbar { width: 4px; height: 4px; }
|
||||||
@@ -226,6 +226,32 @@ const css = `
|
|||||||
color: ${T.textDim}; font-weight: 600; margin-bottom: 8px; }
|
color: ${T.textDim}; font-weight: 600; margin-bottom: 8px; }
|
||||||
.card { background: ${T.panel}; border: 1px solid ${T.border}; border-radius: 8px; padding: 14px; }
|
.card { background: ${T.panel}; border: 1px solid ${T.border}; border-radius: 8px; padding: 14px; }
|
||||||
.card-sm { background: ${T.surface}; border: 1px solid ${T.border}; border-radius: 6px; padding: 10px; }
|
.card-sm { background: ${T.surface}; border: 1px solid ${T.border}; border-radius: 6px; padding: 10px; }
|
||||||
|
|
||||||
|
/* ── Responsive: narrow screens ── */
|
||||||
|
@media (max-width: 640px) {
|
||||||
|
.resp-hide-narrow { display: none !important; }
|
||||||
|
.resp-status-label { font-size: 8px; }
|
||||||
|
.resp-container { max-width: 100% !important; }
|
||||||
|
.resp-tight-pad { padding: 6px 10px; }
|
||||||
|
.param-panel { padding: 6px 10px 5px; }
|
||||||
|
.param-knobs { gap: 6px; }
|
||||||
|
.screen-header { padding: 8px 10px 6px; }
|
||||||
|
.screen-title { font-size: 11px; }
|
||||||
|
.screen-body { padding: 8px 10px; gap: 8px; }
|
||||||
|
.knob-wrap { transform: scale(.9); }
|
||||||
|
.btn-icon { width: 24px; height: 24px; font-size: 10px; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ── Responsive: landscape short ── */
|
||||||
|
@media (orientation: landscape) and (max-height: 500px) {
|
||||||
|
.resp-status-bar { min-height: 26px; padding: 2px 10px; }
|
||||||
|
.resp-param-thumb { height: 26px; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ── Responsive: medium screens (tablet portrait / landscape phone) ── */
|
||||||
|
@media (min-width: 641px) and (max-width: 1024px) {
|
||||||
|
.resp-sidebar-compact { max-width: 70px; }
|
||||||
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
// ── Knob ──────────────────────────────────────────────────────
|
// ── Knob ──────────────────────────────────────────────────────
|
||||||
@@ -468,6 +494,23 @@ export default function App(){
|
|||||||
const [modelBrowserBlockId,setModelBrowserBlockId]=useState(null);
|
const [modelBrowserBlockId,setModelBrowserBlockId]=useState(null);
|
||||||
const [footswitchMode,setFootswitchMode]=useState("stomp");
|
const [footswitchMode,setFootswitchMode]=useState("stomp");
|
||||||
const [addBlockType,setAddBlockType]=useState(null); // null | "picker"
|
const [addBlockType,setAddBlockType]=useState(null); // null | "picker"
|
||||||
|
const [sidebarOpen, setSidebarOpen] = useState(true);
|
||||||
|
|
||||||
|
// ── Responsive breakpoints ──
|
||||||
|
const [isNarrow, setIsNarrow] = useState(window.innerWidth < 640);
|
||||||
|
const [isLandscapeShort, setIsLandscapeShort] = useState(window.innerWidth > window.innerHeight && window.innerHeight < 500);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const mqNarrow = window.matchMedia("(max-width: 640px)");
|
||||||
|
const mqShort = window.matchMedia("(orientation: landscape) and (max-height: 500px)");
|
||||||
|
const onNarrow = (e) => setIsNarrow(e.matches);
|
||||||
|
const onShort = (e) => setIsLandscapeShort(e.matches);
|
||||||
|
mqNarrow.addEventListener("change", onNarrow);
|
||||||
|
mqShort.addEventListener("change", onShort);
|
||||||
|
// Initialize sidebar state
|
||||||
|
if (mqNarrow.matches) setSidebarOpen(false);
|
||||||
|
return () => { mqNarrow.removeEventListener("change", onNarrow); mqShort.removeEventListener("change", onShort); };
|
||||||
|
}, []);
|
||||||
|
|
||||||
// ── Undo/Redo ──
|
// ── Undo/Redo ──
|
||||||
const [undoStack, setUndoStack] = useState([]);
|
const [undoStack, setUndoStack] = useState([]);
|
||||||
@@ -794,19 +837,24 @@ export default function App(){
|
|||||||
return(
|
return(
|
||||||
<><style>{css}</style>
|
<><style>{css}</style>
|
||||||
<div style={{width:"100%",height:"100vh",display:"flex",flexDirection:"column",background:T.bg,overflow:"hidden",
|
<div style={{width:"100%",height:"100vh",display:"flex",flexDirection:"column",background:T.bg,overflow:"hidden",
|
||||||
fontFamily:"'Inter',sans-serif",margin:"0 auto",
|
fontFamily:"'Space Grotesk',sans-serif",margin:"0 auto",
|
||||||
maxWidth:980,
|
maxWidth:isNarrow?undefined:980,
|
||||||
}}>
|
}}>
|
||||||
|
|
||||||
{view==="main"&&(
|
{view==="main"&&(
|
||||||
<>
|
<>
|
||||||
{/* ══════ STATUS BAR ══════ */}
|
{/* ══════ STATUS BAR ══════ */}
|
||||||
<div style={{display:"flex",justifyContent:"space-between",alignItems:"center",
|
<div className="resp-status-bar" style={{display:"flex",justifyContent:"space-between",alignItems:"center",
|
||||||
padding:"4px 12px",background:T.panel,borderBottom:`1px solid ${T.border}`,flexShrink:0,minHeight:32}}>
|
padding:isLandscapeShort?"2px 10px":"4px 12px",background:T.panel,borderBottom:`1px solid ${T.border}`,flexShrink:0,minHeight:isLandscapeShort?26:32}}>
|
||||||
<div style={{display:"flex",gap:8,alignItems:"center"}}>
|
<div style={{display:"flex",gap:8,alignItems:"center"}}>
|
||||||
|
{/* Sidebar toggle (narrow only) */}
|
||||||
|
{isNarrow&&<button className="btn-icon" style={{width:24,height:24,fontSize:13,position:'relative',marginRight:-2}}
|
||||||
|
onClick={()=>setSidebarOpen(s=>!s)} title="Presets">
|
||||||
|
<span style={{fontSize:12,lineHeight:1}}>▤</span>
|
||||||
|
</button>}
|
||||||
<div style={{width:6,height:6,borderRadius:"50%",
|
<div style={{width:6,height:6,borderRadius:"50%",
|
||||||
background:state.connected?T.green:T.red,boxShadow:`0 0 6px ${state.connected?T.green:T.red}`}}/>
|
background:state.connected?T.green:T.red,boxShadow:`0 0 6px ${state.connected?T.green:T.red}`}}/>
|
||||||
<span className="mono" style={{fontSize:9,color:state.connected?T.green:T.red}}>{state.connected?"CONNECTED":"OFFLINE"}</span>
|
{!isNarrow&&<span className="mono" style={{fontSize:9,color:state.connected?T.green:T.red}}>{state.connected?"CONNECTED":"OFFLINE"}</span>}
|
||||||
{/* Undo/Redo */}
|
{/* Undo/Redo */}
|
||||||
<button className="btn-icon" style={{width:20,height:20,fontSize:11,opacity:undoStack.length>0?1:0.3}}
|
<button className="btn-icon" style={{width:20,height:20,fontSize:11,opacity:undoStack.length>0?1:0.3}}
|
||||||
onClick={handleUndo} disabled={undoStack.length===0} title="Undo (Ctrl+Z)">
|
onClick={handleUndo} disabled={undoStack.length===0} title="Undo (Ctrl+Z)">
|
||||||
@@ -823,10 +871,10 @@ export default function App(){
|
|||||||
{loadingPreset&&<span className="mono" style={{fontSize:8,color:T.amber}}>⟳</span>}
|
{loadingPreset&&<span className="mono" style={{fontSize:8,color:T.amber}}>⟳</span>}
|
||||||
</div>
|
</div>
|
||||||
<div style={{display:"flex",gap:8,alignItems:"center"}}>
|
<div style={{display:"flex",gap:8,alignItems:"center"}}>
|
||||||
<div style={{display:"flex",gap:8,alignItems:"center"}}>
|
{!isNarrow&&<div style={{display:"flex",gap:8,alignItems:"center"}}>
|
||||||
<VUMeter level={vuLevel} height={24}/>
|
<VUMeter level={vuLevel} height={24}/>
|
||||||
<span className="mono" style={{fontSize:9,color:T.textSec}}>CPU <span style={{color:T.amber,fontWeight:700}}>{state.cpu_percent!=null?`${state.cpu_percent}%`:"—"}</span></span>
|
<span className="mono" style={{fontSize:9,color:T.textSec}}>CPU <span style={{color:T.amber,fontWeight:700}}>{state.cpu_percent!=null?`${state.cpu_percent}%`:"—"}</span></span>
|
||||||
</div>
|
</div>}
|
||||||
<div style={{width:1,height:12,background:T.border}}/>
|
<div style={{width:1,height:12,background:T.border}}/>
|
||||||
<button className="btn-icon" style={{width:24,height:24,position:'relative'}}onClick={()=>setView("captures")}title="Downloads">
|
<button className="btn-icon" style={{width:24,height:24,position:'relative'}}onClick={()=>setView("captures")}title="Downloads">
|
||||||
<img src={`${import.meta.env.BASE_URL}img/ic_bank.svg`} alt="captures" style={{width:14,height:14}}/>
|
<img src={`${import.meta.env.BASE_URL}img/ic_bank.svg`} alt="captures" style={{width:14,height:14}}/>
|
||||||
@@ -866,8 +914,22 @@ export default function App(){
|
|||||||
<div style={{flex:1,display:"flex",overflow:"hidden"}}>
|
<div style={{flex:1,display:"flex",overflow:"hidden"}}>
|
||||||
|
|
||||||
{/* ─── Preset Sidebar ─── */}
|
{/* ─── Preset Sidebar ─── */}
|
||||||
<div style={{width:90,flexShrink:0,background:T.surface,borderRight:`1px solid ${T.border}`,
|
{(!isNarrow || sidebarOpen)&&<div style={{
|
||||||
display:"flex",flexDirection:"column",overflow:"hidden"}}>
|
width:isNarrow?"100%":90,flexShrink:0,background:T.surface,
|
||||||
|
borderRight:isNarrow?"none":`1px solid ${T.border}`,
|
||||||
|
borderBottom:isNarrow?`1px solid ${T.border}`:"none",
|
||||||
|
display:"flex",flexDirection:"column",overflow:"hidden",
|
||||||
|
position:isNarrow?"fixed":"relative",
|
||||||
|
zIndex:isNarrow?50:"auto",
|
||||||
|
left:0,right:0,
|
||||||
|
top:"auto",
|
||||||
|
bottom:isNarrow?0:"auto",
|
||||||
|
height:isNarrow?140:"100%",
|
||||||
|
borderTopLeftRadius:isNarrow?12:0,
|
||||||
|
borderTopRightRadius:isNarrow?12:0,
|
||||||
|
boxShadow:isNarrow?"0 -4px 24px rgba(0,0,0,.6)":"none",
|
||||||
|
transform:isNarrow&&sidebarOpen?"translateY(0)":"none",
|
||||||
|
}}>
|
||||||
{/* Bank header */}
|
{/* Bank header */}
|
||||||
<div style={{padding:"6px 8px",textAlign:"center",borderBottom:`1px solid ${T.border}`,background:T.panel}}>
|
<div style={{padding:"6px 8px",textAlign:"center",borderBottom:`1px solid ${T.border}`,background:T.panel}}>
|
||||||
<div className="mono" style={{fontSize:14,fontWeight:700,color:T.amber}}>Bank {bankLetter}</div>
|
<div className="mono" style={{fontSize:14,fontWeight:700,color:T.amber}}>Bank {bankLetter}</div>
|
||||||
@@ -885,7 +947,10 @@ export default function App(){
|
|||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>}
|
||||||
|
{/* Backdrop for narrow sidebar */}
|
||||||
|
{isNarrow&&sidebarOpen&&<div style={{position:"fixed",inset:0,zIndex:49,background:"rgba(0,0,0,.5)"}}
|
||||||
|
onClick={()=>setSidebarOpen(false)}/>}
|
||||||
|
|
||||||
{/* ─── Main Content Area ─── */}
|
{/* ─── Main Content Area ─── */}
|
||||||
<div style={{flex:1,display:"flex",flexDirection:"column",overflow:"hidden",minWidth:0}}>
|
<div style={{flex:1,display:"flex",flexDirection:"column",overflow:"hidden",minWidth:0}}>
|
||||||
|
|||||||
+1
-1
@@ -338,7 +338,7 @@ export default function FocusView({
|
|||||||
position: 'fixed', inset: 0, zIndex: 1000,
|
position: 'fixed', inset: 0, zIndex: 1000,
|
||||||
display: 'flex', flexDirection: 'column',
|
display: 'flex', flexDirection: 'column',
|
||||||
background: T.bg,
|
background: T.bg,
|
||||||
fontFamily: "'Inter', sans-serif",
|
fontFamily: "'Space Grotesk', sans-serif",
|
||||||
color: T.textPrimary,
|
color: T.textPrimary,
|
||||||
}}>
|
}}>
|
||||||
{/* ── Header ── */}
|
{/* ── Header ── */}
|
||||||
|
|||||||
+1
-1
@@ -265,7 +265,7 @@ export default function GlobalEQ({ onClose }) {
|
|||||||
position: "fixed", inset: 0, zIndex: 998,
|
position: "fixed", inset: 0, zIndex: 998,
|
||||||
display: "flex", flexDirection: "column",
|
display: "flex", flexDirection: "column",
|
||||||
background: T.bg, color: T.textPrimary,
|
background: T.bg, color: T.textPrimary,
|
||||||
fontFamily: "'Inter', sans-serif",
|
fontFamily: "'Space Grotesk', sans-serif",
|
||||||
}}>
|
}}>
|
||||||
{/* Header */}
|
{/* Header */}
|
||||||
<div style={{
|
<div style={{
|
||||||
|
|||||||
@@ -394,7 +394,7 @@ export default function GlobalSettings({ onClose, onMasterVolume, onAudioProfile
|
|||||||
}, [savedValues]);
|
}, [savedValues]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div style={{ position: "fixed", inset: 0, zIndex: 998, display: "flex", flexDirection: "column", background: T.bg, color: T.textPrimary, fontFamily: "'Inter', sans-serif" }}>
|
<div style={{ position: "fixed", inset: 0, zIndex: 998, display: "flex", flexDirection: "column", background: T.bg, color: T.textPrimary, fontFamily: "'Space Grotesk', sans-serif" }}>
|
||||||
<div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", padding: "10px 14px", borderBottom: `1px solid ${T.border}`, background: T.panel, flexShrink: 0 }}>
|
<div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", padding: "10px 14px", borderBottom: `1px solid ${T.border}`, background: T.panel, flexShrink: 0 }}>
|
||||||
<div style={{ display: "flex", alignItems: "center", gap: 10 }}>
|
<div style={{ display: "flex", alignItems: "center", gap: 10 }}>
|
||||||
<button onClick={onClose} style={{ width: 34, height: 34, borderRadius: 8, display: "flex", alignItems: "center", justifyContent: "center", background: T.surface, border: `1px solid ${T.border}`, color: T.textPrimary, fontSize: 16, cursor: "pointer" }}>✕</button>
|
<button onClick={onClose} style={{ width: 34, height: 34, borderRadius: 8, display: "flex", alignItems: "center", justifyContent: "center", background: T.surface, border: `1px solid ${T.border}`, color: T.textPrimary, fontSize: 16, cursor: "pointer" }}>✕</button>
|
||||||
|
|||||||
@@ -365,7 +365,7 @@ export default function ModelBrowser({
|
|||||||
display: "flex", flexDirection: "column",
|
display: "flex", flexDirection: "column",
|
||||||
background: T.bg,
|
background: T.bg,
|
||||||
color: T.textPrimary,
|
color: T.textPrimary,
|
||||||
fontFamily: "'Inter', sans-serif",
|
fontFamily: "'Space Grotesk', sans-serif",
|
||||||
}}>
|
}}>
|
||||||
{/* ── Header ── */}
|
{/* ── Header ── */}
|
||||||
<div style={{
|
<div style={{
|
||||||
|
|||||||
@@ -1,3 +1,20 @@
|
|||||||
|
/* ── CSS custom properties (design tokens) ── */
|
||||||
|
:root {
|
||||||
|
--bg: #0A0A0C;
|
||||||
|
--panel: #141418;
|
||||||
|
--surface: #1C1C22;
|
||||||
|
--border: #2A2A32;
|
||||||
|
--amber: #E8A030;
|
||||||
|
--amber-dim: #7A5218;
|
||||||
|
--blue: #4A8BC8;
|
||||||
|
--blue-dim: #1E4060;
|
||||||
|
--green: #3AB87A;
|
||||||
|
--red: #E06060;
|
||||||
|
--text-primary: #F0EDE6;
|
||||||
|
--text-sec: #A0A0BC;
|
||||||
|
--text-dim: #7878A0;
|
||||||
|
}
|
||||||
|
|
||||||
/* ── Reset & base ── */
|
/* ── Reset & base ── */
|
||||||
* { margin: 0; padding: 0; box-sizing: border-box; }
|
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||||||
html, body, #root { height: 100%; overflow: hidden; }
|
html, body, #root { height: 100%; overflow: hidden; }
|
||||||
|
|||||||
Reference in New Issue
Block a user