diff --git a/public/app.css b/public/app.css
index 16a52bd..b2265a5 100644
--- a/public/app.css
+++ b/public/app.css
@@ -1,467 +1,1445 @@
/* Roast Planner — screen UI. worksheet.css is print-only (loaded with media="print"); this file
owns the entire on-screen experience and is deliberately independent of the print layout. */
-:root{
- --ink:#1B1614; --ink-2:#5B524B; --ink-3:#8C8179;
- --surface:#FBF8F4; --surface-raised:#FFFFFF; --surface-sunken:#F2ECE4;
- --line:#E4DCD2; --line-strong:#D3C8BA;
- --ember:#A8481A; --ember-soft:#FBEFE6; --ember-strong:#7F350F;
- --pass:#2F6F4E; --pass-bg:#E8F3ED;
- --warn:#A8741A; --warn-bg:#FBF3E1;
- --fail:#B03A22; --fail-bg:#FBEAE5;
- --radius-sm:6px; --radius-md:10px; --radius-lg:16px;
- --shadow-card:0 1px 2px rgba(27,22,20,.04), 0 8px 24px -12px rgba(27,22,20,.12);
- --shadow-pop:0 12px 32px -8px rgba(27,22,20,.28);
- --font-ui:-apple-system,BlinkMacSystemFont,"SF Pro Text","Segoe UI",Inter,Helvetica,Arial,sans-serif;
- --font-serif:"Iowan Old Style","Palatino Linotype",Palatino,Georgia,"Times New Roman",serif;
- --font-mono:"SF Mono",Menlo,Consolas,monospace;
- --header-h:60px;
+:root {
+ --ink: #1b1614;
+ --ink-2: #5b524b;
+ --ink-3: #8c8179;
+ --surface: #fbf8f4;
+ --surface-raised: #ffffff;
+ --surface-sunken: #f2ece4;
+ --line: #e4dcd2;
+ --line-strong: #d3c8ba;
+ --ember: #a8481a;
+ --ember-soft: #fbefe6;
+ --ember-strong: #7f350f;
+ --pass: #2f6f4e;
+ --pass-bg: #e8f3ed;
+ --warn: #a8741a;
+ --warn-bg: #fbf3e1;
+ --fail: #b03a22;
+ --fail-bg: #fbeae5;
+ --radius-sm: 6px;
+ --radius-md: 10px;
+ --radius-lg: 16px;
+ --shadow-card:
+ 0 1px 2px rgba(27, 22, 20, 0.04), 0 8px 24px -12px rgba(27, 22, 20, 0.12);
+ --shadow-pop: 0 12px 32px -8px rgba(27, 22, 20, 0.28);
+ --font-ui:
+ -apple-system, BlinkMacSystemFont, "SF Pro Text", "Segoe UI", Inter,
+ Helvetica, Arial, sans-serif;
+ --font-serif:
+ "Iowan Old Style", "Palatino Linotype", Palatino, Georgia,
+ "Times New Roman", serif;
+ --font-mono: "SF Mono", Menlo, Consolas, monospace;
+ --header-h: 60px;
}
-*{ box-sizing:border-box; }
-.hidden{ display:none !important; }
-html{ background:var(--surface); }
-body{
- margin:0; background:var(--surface); color:var(--ink);
- font-family:var(--font-ui); font-size:15px; line-height:1.45;
- -webkit-font-smoothing:antialiased;
+* {
+ box-sizing: border-box;
+}
+.hidden {
+ display: none !important;
+}
+html {
+ background: var(--surface);
+}
+body {
+ margin: 0;
+ background: var(--surface);
+ color: var(--ink);
+ font-family: var(--font-ui);
+ font-size: 15px;
+ line-height: 1.45;
+ -webkit-font-smoothing: antialiased;
+}
+h1,
+h2,
+h3 {
+ margin: 0;
+ font-family: var(--font-ui);
+}
+output {
+ font-variant-numeric: tabular-nums;
}
-h1,h2,h3{ margin:0; font-family:var(--font-ui); }
-output{ font-variant-numeric:tabular-nums; }
/* ─── Header ──────────────────────────────────────────────────────────── */
-.app-header{
- position:sticky; top:0; z-index:30; height:var(--header-h);
- display:flex; align-items:center; gap:24px;
- background:var(--surface-raised); border-bottom:1px solid var(--line);
- padding:0 20px;
+.app-header {
+ position: sticky;
+ top: 0;
+ z-index: 30;
+ height: var(--header-h);
+ display: flex;
+ align-items: center;
+ gap: 24px;
+ background: var(--surface-raised);
+ border-bottom: 1px solid var(--line);
+ padding: 0 20px;
+}
+.brand {
+ display: flex;
+ align-items: center;
+ gap: 10px;
+ flex: 0 0 auto;
+}
+.brand-mark {
+ font-size: 22px;
+ color: var(--ember);
+ line-height: 1;
+}
+.brand-text h1 {
+ font-size: 15px;
+ font-weight: 700;
+ letter-spacing: -0.1px;
+}
+.brand-sub {
+ margin: 0;
+ font-size: 11.5px;
+ color: var(--ink-3);
}
-.brand{ display:flex; align-items:center; gap:10px; flex:0 0 auto; }
-.brand-mark{ font-size:22px; color:var(--ember); line-height:1; }
-.brand-text h1{ font-size:15px; font-weight:700; letter-spacing:-.1px; }
-.brand-sub{ margin:0; font-size:11.5px; color:var(--ink-3); }
-.section-nav{
- display:flex; align-items:center; gap:2px; flex:1 1 auto; overflow-x:auto;
- scrollbar-width:none;
+.section-nav {
+ display: flex;
+ align-items: center;
+ gap: 2px;
+ flex: 1 1 auto;
+ overflow-x: auto;
+ scrollbar-width: none;
}
-.section-nav::-webkit-scrollbar{ display:none; }
-.section-nav a{
- flex:0 0 auto; padding:6px 12px; border-radius:999px; font-size:12.5px; font-weight:500;
- color:var(--ink-2); text-decoration:none; white-space:nowrap; transition:background .15s,color .15s;
+.section-nav::-webkit-scrollbar {
+ display: none;
+}
+.section-nav a {
+ flex: 0 0 auto;
+ padding: 6px 12px;
+ border-radius: 999px;
+ font-size: 12.5px;
+ font-weight: 500;
+ color: var(--ink-2);
+ text-decoration: none;
+ white-space: nowrap;
+ transition:
+ background 0.15s,
+ color 0.15s;
+}
+.section-nav a:hover {
+ background: var(--surface-sunken);
+ color: var(--ink);
+}
+.section-nav a.active {
+ background: var(--ember-soft);
+ color: var(--ember-strong);
+ font-weight: 600;
}
-.section-nav a:hover{ background:var(--surface-sunken); color:var(--ink); }
-.section-nav a.active{ background:var(--ember-soft); color:var(--ember-strong); font-weight:600; }
-.header-actions{ display:flex; align-items:center; gap:8px; flex:0 0 auto; }
-.header-divider{ width:1px; height:22px; background:var(--line); margin:0 2px; }
-
-.ghost-btn, .primary-btn, label.filebtn{
- font-family:var(--font-ui); font-size:12.5px; font-weight:600; cursor:pointer;
- border-radius:var(--radius-sm); padding:7px 12px; white-space:nowrap;
- border:1px solid transparent; transition:background .15s,border-color .15s,color .15s;
+.header-actions {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ flex: 0 0 auto;
}
-.ghost-btn{ background:transparent; color:var(--ink-2); border-color:var(--line); }
-.ghost-btn:hover{ background:var(--surface-sunken); color:var(--ink); }
-.ghost-btn[aria-pressed="true"]{ background:var(--ember-soft); border-color:var(--ember); color:var(--ember-strong); }
-.ghost-btn.small{ font-size:12px; padding:5px 10px; }
-.ghost-btn:disabled{ opacity:.45; cursor:default; }
-.primary-btn, label.filebtn{ background:var(--ember); color:#fff; border-color:var(--ember); }
-.primary-btn:hover, label.filebtn:hover{ background:var(--ember-strong); }
-.primary-btn:disabled{ opacity:.5; cursor:default; }
-#file-load{ display:none; }
-label.filebtn input[type=file]{ display:none; }
+.header-divider {
+ width: 1px;
+ height: 22px;
+ background: var(--line);
+ margin: 0 2px;
+}
+.account-menu { position: relative; }
+.account-menu summary { list-style: none; }
+.account-menu summary::-webkit-details-marker { display: none; }
+.account-menu-popover {
+ position: absolute; right: 0; top: calc(100% + 6px); z-index: 35; min-width: 132px;
+ padding: 6px; border: 1px solid var(--line); border-radius: var(--radius-sm);
+ background: var(--surface-raised); box-shadow: var(--shadow-pop);
+}
+.account-menu-popover a, .account-menu-popover button {
+ display: block; width: 100%; padding: 9px 10px; border: 0; border-radius: var(--radius-sm);
+ background: transparent; color: var(--ink-2); font: inherit; font-size: 13px; text-align: left;
+ text-decoration: none; cursor: pointer;
+}
+.account-menu-popover a:hover, .account-menu-popover button:hover { background: var(--surface-sunken); color: var(--ink); }
-.autosave-chip{
- display:flex; align-items:center; gap:6px; font-size:11.5px; color:var(--ink-3);
- padding:4px 10px; border-radius:999px; background:var(--surface-sunken); margin-left:2px;
+.ghost-btn,
+.primary-btn,
+label.filebtn {
+ font-family: var(--font-ui);
+ font-size: 12.5px;
+ font-weight: 600;
+ cursor: pointer;
+ border-radius: var(--radius-sm);
+ padding: 7px 12px;
+ white-space: nowrap;
+ border: 1px solid transparent;
+ transition:
+ background 0.15s,
+ border-color 0.15s,
+ color 0.15s;
+}
+.ghost-btn {
+ background: transparent;
+ color: var(--ink-2);
+ border-color: var(--line);
+}
+.ghost-btn:hover {
+ background: var(--surface-sunken);
+ color: var(--ink);
+}
+.ghost-btn[aria-pressed="true"] {
+ background: var(--ember-soft);
+ border-color: var(--ember);
+ color: var(--ember-strong);
+}
+.ghost-btn.small {
+ font-size: 12px;
+ padding: 5px 10px;
+}
+.ghost-btn:disabled {
+ opacity: 0.45;
+ cursor: default;
+}
+.primary-btn,
+label.filebtn {
+ background: var(--ember);
+ color: #fff;
+ border-color: var(--ember);
+}
+.primary-btn:hover,
+label.filebtn:hover {
+ background: var(--ember-strong);
+}
+.primary-btn:disabled {
+ opacity: 0.5;
+ cursor: default;
+}
+#file-load {
+ display: none;
+}
+label.filebtn input[type="file"] {
+ display: none;
+}
+
+.autosave-chip {
+ display: flex;
+ align-items: center;
+ gap: 6px;
+ font-size: 11.5px;
+ color: var(--ink-3);
+ padding: 4px 10px;
+ border-radius: 999px;
+ background: var(--surface-sunken);
+ margin-left: 2px;
+}
+.autosave-chip .dot {
+ width: 6px;
+ height: 6px;
+ border-radius: 50%;
+ background: var(--ink-3);
+ transition: background 0.2s;
+}
+.autosave-chip.saving .dot {
+ background: var(--warn);
+ animation: pulse 1s ease-in-out infinite;
+}
+.autosave-chip.saved .dot {
+ background: var(--pass);
+}
+@keyframes pulse {
+ 0%,
+ 100% {
+ opacity: 1;
+ }
+ 50% {
+ opacity: 0.35;
+ }
}
-.autosave-chip .dot{ width:6px; height:6px; border-radius:50%; background:var(--ink-3); transition:background .2s; }
-.autosave-chip.saving .dot{ background:var(--warn); animation:pulse 1s ease-in-out infinite; }
-.autosave-chip.saved .dot{ background:var(--pass); }
-@keyframes pulse{ 0%,100%{ opacity:1; } 50%{ opacity:.35; } }
/* ─── Drawers ─────────────────────────────────────────────────────────── */
-.drawer-overlay{
- position:fixed; inset:0; background:rgba(27,22,20,.32); z-index:40; opacity:1; transition:opacity .18s;
+.drawer-overlay {
+ position: fixed;
+ inset: 0;
+ background: rgba(27, 22, 20, 0.32);
+ z-index: 40;
+ opacity: 1;
+ transition: opacity 0.18s;
}
-.drawer-overlay.hidden{ display:none; }
-.drawer{
- position:fixed; top:0; right:0; bottom:0; width:min(420px,92vw); z-index:41;
- background:var(--surface-raised); box-shadow:var(--shadow-pop);
- display:flex; flex-direction:column; transform:translateX(0); transition:transform .2s;
+.drawer-overlay.hidden {
+ display: none;
}
-.drawer.hidden{ display:none; }
-.drawer-head{
- display:flex; align-items:center; justify-content:space-between;
- padding:16px 20px; border-bottom:1px solid var(--line);
+.drawer {
+ position: fixed;
+ top: 0;
+ right: 0;
+ bottom: 0;
+ width: min(420px, 92vw);
+ z-index: 41;
+ background: var(--surface-raised);
+ box-shadow: var(--shadow-pop);
+ display: flex;
+ flex-direction: column;
+ transform: translateX(0);
+ transition: transform 0.2s;
}
-.drawer-head h3{ font-size:14.5px; font-weight:700; }
-.icon-btn{
- background:none; border:none; font-size:14px; color:var(--ink-3); cursor:pointer;
- width:28px; height:28px; border-radius:var(--radius-sm);
+.drawer.hidden {
+ display: none;
}
-.icon-btn:hover{ background:var(--surface-sunken); color:var(--ink); }
-.drawer-body{ padding:18px 20px; overflow-y:auto; display:flex; flex-direction:column; gap:12px; }
-.stack-label{ font-size:12px; font-weight:600; color:var(--ink-2); }
-.text-input{
- width:100%; padding:9px 11px; border:1px solid var(--line); border-radius:var(--radius-sm);
- font-size:13.5px; font-family:var(--font-ui); background:var(--surface-raised); color:var(--ink);
+.drawer-head {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ padding: 16px 20px;
+ border-bottom: 1px solid var(--line);
+}
+.drawer-head h3 {
+ font-size: 14.5px;
+ font-weight: 700;
+}
+.icon-btn {
+ background: none;
+ border: none;
+ font-size: 14px;
+ color: var(--ink-3);
+ cursor: pointer;
+ width: 28px;
+ height: 28px;
+ border-radius: var(--radius-sm);
+}
+.icon-btn:hover {
+ background: var(--surface-sunken);
+ color: var(--ink);
+}
+.drawer-body {
+ padding: 18px 20px;
+ overflow-y: auto;
+ display: flex;
+ flex-direction: column;
+ gap: 12px;
+}
+.stack-label {
+ font-size: 12px;
+ font-weight: 600;
+ color: var(--ink-2);
+}
+.text-input {
+ width: 100%;
+ padding: 9px 11px;
+ border: 1px solid var(--line);
+ border-radius: var(--radius-sm);
+ font-size: 13.5px;
+ font-family: var(--font-ui);
+ background: var(--surface-raised);
+ color: var(--ink);
+}
+.text-input:focus {
+ outline: none;
+ border-color: var(--ember);
+ box-shadow: 0 0 0 3px var(--ember-soft);
+}
+.checkbox-row {
+ display: flex;
+ align-items: center;
+ gap: 7px;
+ font-size: 13px;
+ color: var(--ink-2);
+}
+.drawer-actions {
+ display: flex;
+ gap: 8px;
+}
+.drawer-result {
+ font-size: 12.5px;
+ color: var(--ink-2);
+ line-height: 1.55;
+}
+.drawer-result a {
+ color: var(--ember);
+}
+.drawer-result .warnings {
+ color: var(--warn);
+ margin: 6px 0 0;
+ padding-left: 18px;
+}
+.lib-list {
+ list-style: none;
+ margin: 0;
+ padding: 0;
+ max-height: 220px;
+ overflow-y: auto;
+ border: 1px solid var(--line);
+ border-radius: var(--radius-sm);
+}
+.lib-list.hidden {
+ display: none;
+}
+.lib-list li {
+ padding: 8px 10px;
+ font-size: 12.5px;
+ border-bottom: 1px solid var(--line);
+ cursor: pointer;
+}
+.lib-list li:last-child {
+ border-bottom: none;
+}
+.lib-list li:hover {
+ background: var(--surface-sunken);
}
-.text-input:focus{ outline:none; border-color:var(--ember); box-shadow:0 0 0 3px var(--ember-soft); }
-.checkbox-row{ display:flex; align-items:center; gap:7px; font-size:13px; color:var(--ink-2); }
-.drawer-actions{ display:flex; gap:8px; }
-.drawer-result{ font-size:12.5px; color:var(--ink-2); line-height:1.55; }
-.drawer-result a{ color:var(--ember); }
-.drawer-result .warnings{ color:var(--warn); margin:6px 0 0; padding-left:18px; }
-.lib-list{ list-style:none; margin:0; padding:0; max-height:220px; overflow-y:auto; border:1px solid var(--line); border-radius:var(--radius-sm); }
-.lib-list.hidden{ display:none; }
-.lib-list li{ padding:8px 10px; font-size:12.5px; border-bottom:1px solid var(--line); cursor:pointer; }
-.lib-list li:last-child{ border-bottom:none; }
-.lib-list li:hover{ background:var(--surface-sunken); }
/* ─── Workspace layout ────────────────────────────────────────────────── */
-.workspace-grid{
- display:grid; grid-template-columns:1fr 380px; gap:28px; align-items:start;
- max-width:1360px; margin:0 auto; padding:28px 24px 80px;
+.workspace-grid {
+ display: grid;
+ grid-template-columns: 1fr 380px;
+ gap: 28px;
+ align-items: start;
+ max-width: 1360px;
+ margin: 0 auto;
+ padding: 28px 24px 80px;
}
-.form-col{ min-width:0; display:flex; flex-direction:column; }
-.dock{
- position:sticky; top:calc(var(--header-h) + 20px);
- display:flex; flex-direction:column; gap:18px;
- max-height:calc(100vh - var(--header-h) - 40px); overflow-y:auto;
- padding-bottom:4px;
+.form-col {
+ min-width: 0;
+ display: flex;
+ flex-direction: column;
+}
+.dock {
+ position: sticky;
+ top: calc(var(--header-h) + 20px);
+ display: flex;
+ flex-direction: column;
+ gap: 18px;
+ max-height: calc(100vh - var(--header-h) - 40px);
+ overflow-y: auto;
+ padding-bottom: 4px;
}
-@media (max-width:1180px){
- .workspace-grid{ grid-template-columns:1fr; }
- .dock{ position:static; max-height:none; }
+@media (max-width: 1180px) {
+ .workspace-grid {
+ grid-template-columns: 1fr;
+ }
+ .dock {
+ position: static;
+ max-height: none;
+ }
}
-@media (max-width:1080px){
- .app-header{ flex-wrap:wrap; height:auto; padding:10px 14px; gap:10px; }
- .section-nav{ order:3; flex-basis:100%; }
+@media (max-width: 1080px) {
+ .app-header {
+ flex-wrap: wrap;
+ height: auto;
+ padding: 10px 14px;
+ gap: 10px;
+ }
+ .section-nav {
+ order: 3;
+ flex-basis: 100%;
+ }
}
-@media (max-width:720px){
- .workspace-grid{ padding:18px 14px 60px; }
+@media (max-width: 720px) {
+ .workspace-grid {
+ padding: 18px 14px 60px;
+ }
}
/* ─── Panel cards (form sections) ────────────────────────────────────── */
-.panel-card{
- background:var(--surface-raised); border:1px solid var(--line); border-radius:var(--radius-lg);
- margin-bottom:20px; box-shadow:var(--shadow-card);
+.panel-card {
+ background: var(--surface-raised);
+ border: 1px solid var(--line);
+ border-radius: var(--radius-lg);
+ margin-bottom: 20px;
+ box-shadow: var(--shadow-card);
}
-.panel-head{
- display:flex; align-items:center; justify-content:space-between; gap:16px;
- padding:16px 22px; border-bottom:1px solid var(--line);
+.panel-head {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ gap: 16px;
+ padding: 16px 22px;
+ border-bottom: 1px solid var(--line);
}
-.panel-head h2{ font-size:16px; font-weight:700; letter-spacing:-.1px; }
-.panel-body{ padding:20px 22px 22px; }
-.subhead{
- font-size:11px; text-transform:uppercase; letter-spacing:.06em; font-weight:700;
- color:var(--ink-3); margin:20px 0 12px;
+.panel-head h2 {
+ font-size: 16px;
+ font-weight: 700;
+ letter-spacing: -0.1px;
+}
+.panel-body {
+ padding: 20px 22px 22px;
+}
+.subhead {
+ font-size: 11px;
+ text-transform: uppercase;
+ letter-spacing: 0.06em;
+ font-weight: 700;
+ color: var(--ink-3);
+ margin: 20px 0 12px;
+}
+.subhead:first-child {
+ margin-top: 0;
}
-.subhead:first-child{ margin-top:0; }
/* ─── Fields ──────────────────────────────────────────────────────────── */
-.field-grid{
- display:grid; grid-template-columns:repeat(auto-fit,minmax(150px,1fr)); gap:14px 18px; margin-bottom:14px;
+.field-grid {
+ display: grid;
+ grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
+ gap: 14px 18px;
+ margin-bottom: 14px;
}
-.field-grid:last-child{ margin-bottom:0; }
-.field{ position:relative; display:flex; flex-direction:column; gap:5px; }
-.field.wide{ grid-column:1 / -1; }
-.field.accent .field-label{ color:var(--ember-strong); }
-.field-label{
- font-size:12px; font-weight:600; color:var(--ink-2); display:flex; align-items:center; gap:4px;
+.field-grid:last-child {
+ margin-bottom: 0;
}
-.hint{
- font-size:11px; color:var(--ink-3); cursor:help; border-radius:50%; width:14px; height:14px;
- display:inline-flex; align-items:center; justify-content:center;
+.field {
+ position: relative;
+ display: flex;
+ flex-direction: column;
+ gap: 5px;
}
-.field-input{
- width:100%; padding:8px 10px; border:1px solid var(--line); border-radius:var(--radius-sm);
- font-family:var(--font-ui); font-size:13.5px; color:var(--ink); background:var(--surface-raised);
- transition:border-color .15s, box-shadow .15s;
+.field.wide {
+ grid-column: 1 / -1;
+}
+.field.accent .field-label {
+ color: var(--ember-strong);
+}
+.field-label {
+ font-size: 12px;
+ font-weight: 600;
+ color: var(--ink-2);
+ display: flex;
+ align-items: center;
+ gap: 4px;
+}
+.hint {
+ font-size: 11px;
+ color: var(--ink-3);
+ cursor: help;
+ border-radius: 50%;
+ width: 14px;
+ height: 14px;
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+}
+.field-input {
+ width: 100%;
+ padding: 8px 10px;
+ border: 1px solid var(--line);
+ border-radius: var(--radius-sm);
+ font-family: var(--font-ui);
+ font-size: 13.5px;
+ color: var(--ink);
+ background: var(--surface-raised);
+ transition:
+ border-color 0.15s,
+ box-shadow 0.15s;
+}
+.field-input.sm {
+ text-align: center;
+ font-family: var(--font-mono);
+ font-size: 13px;
+}
+.field-input.note {
+ font-family: var(--font-ui);
+}
+.field-input:focus {
+ outline: none;
+ border-color: var(--ember);
+ box-shadow: 0 0 0 3px var(--ember-soft);
+}
+.field-input.prefilled {
+ background: #fff6de;
+ border-color: #e4c766;
+}
+.field-input::placeholder {
+ color: var(--ink-3);
+ opacity: 0.7;
}
-.field-input.sm{ text-align:center; font-family:var(--font-mono); font-size:13px; }
-.field-input.note{ font-family:var(--font-ui); }
-.field-input:focus{ outline:none; border-color:var(--ember); box-shadow:0 0 0 3px var(--ember-soft); }
-.field-input.prefilled{ background:#FFF6DE; border-color:#E4C766; }
-.field-input::placeholder{ color:var(--ink-3); opacity:.7; }
-.unit-input{ position:relative; }
-.unit-input .field-input{ padding-right:32px; }
-.unit-input.sm .field-input{ padding-right:26px; }
-.unit-input .unit{
- position:absolute; right:10px; top:50%; transform:translateY(-50%);
- font-size:11.5px; color:var(--ink-3); pointer-events:none;
+.unit-input {
+ position: relative;
+}
+.unit-input .field-input {
+ padding-right: 32px;
+}
+.unit-input.sm .field-input {
+ padding-right: 26px;
+}
+.unit-input .unit {
+ position: absolute;
+ right: 10px;
+ top: 50%;
+ transform: translateY(-50%);
+ font-size: 11.5px;
+ color: var(--ink-3);
+ pointer-events: none;
+}
+.unit-input.sm .unit {
+ right: 7px;
+ font-size: 10.5px;
}
-.unit-input.sm .unit{ right:7px; font-size:10.5px; }
/* field-id badge — hidden until hover/focus, or pinned via "Field IDs" toggle */
-.field[data-fid]::after{
- content:attr(data-fid); position:absolute; top:-6px; right:0;
- font-family:var(--font-mono); font-size:9.5px; font-weight:700; color:var(--ember);
- background:var(--ember-soft); padding:1px 5px; border-radius:5px;
- opacity:0; transition:opacity .12s; pointer-events:none;
+.field[data-fid]::after {
+ content: attr(data-fid);
+ position: absolute;
+ top: -6px;
+ right: 0;
+ font-family: var(--font-mono);
+ font-size: 9.5px;
+ font-weight: 700;
+ color: var(--ember);
+ background: var(--ember-soft);
+ padding: 1px 5px;
+ border-radius: 5px;
+ opacity: 0;
+ transition: opacity 0.12s;
+ pointer-events: none;
+}
+.field[data-fid]:hover::after,
+.field[data-fid]:focus-within::after {
+ opacity: 1;
+}
+body.show-fids .field[data-fid]::after {
+ opacity: 1;
}
-.field[data-fid]:hover::after, .field[data-fid]:focus-within::after{ opacity:1; }
-body.show-fids .field[data-fid]::after{ opacity:1; }
/* ─── Choice controls (segmented + chips) ───────────────────────────── */
-.segmented{
- display:inline-flex; flex-wrap:wrap; gap:2px; background:var(--surface-sunken);
- padding:2px; border-radius:var(--radius-md);
+.segmented {
+ display: inline-flex;
+ flex-wrap: wrap;
+ gap: 2px;
+ background: var(--surface-sunken);
+ padding: 2px;
+ border-radius: var(--radius-md);
}
-.segmented.small{ padding:2px; }
-.seg-opt{ position:relative; cursor:pointer; }
-.seg-opt input{ position:absolute; opacity:0; width:0; height:0; }
-.seg-opt span{
- display:block; padding:6px 12px; border-radius:8px; font-size:12.5px; font-weight:500;
- color:var(--ink-2); white-space:nowrap; transition:background .15s,color .15s,box-shadow .15s;
+.segmented.small {
+ padding: 2px;
}
-.seg-opt input:checked + span{
- background:var(--surface-raised); color:var(--ember-strong); font-weight:700;
- box-shadow:0 1px 2px rgba(27,22,20,.12);
+.seg-opt {
+ position: relative;
+ cursor: pointer;
+}
+.seg-opt input {
+ position: absolute;
+ opacity: 0;
+ width: 0;
+ height: 0;
+}
+.seg-opt span {
+ display: block;
+ padding: 6px 12px;
+ border-radius: 8px;
+ font-size: 12.5px;
+ font-weight: 500;
+ color: var(--ink-2);
+ white-space: nowrap;
+ transition:
+ background 0.15s,
+ color 0.15s,
+ box-shadow 0.15s;
+}
+.seg-opt input:checked + span {
+ background: var(--surface-raised);
+ color: var(--ember-strong);
+ font-weight: 700;
+ box-shadow: 0 1px 2px rgba(27, 22, 20, 0.12);
+}
+.seg-opt input:focus-visible + span {
+ outline: 2px solid var(--ember);
+ outline-offset: 1px;
}
-.seg-opt input:focus-visible + span{ outline:2px solid var(--ember); outline-offset:1px; }
-.chip-group{ display:flex; flex-wrap:wrap; gap:8px; }
-.chip-opt{ cursor:pointer; }
-.chip-opt input{ position:absolute; opacity:0; width:0; height:0; }
-.chip-opt span{
- display:inline-flex; align-items:center; padding:7px 14px; border-radius:999px;
- border:1px solid var(--line); font-size:12.5px; font-weight:500; color:var(--ink-2);
- background:var(--surface-raised); transition:all .15s;
+.chip-group {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 8px;
}
-.chip-opt input:checked + span{
- background:var(--ember-soft); border-color:var(--ember); color:var(--ember-strong); font-weight:700;
+.chip-opt {
+ cursor: pointer;
+}
+.chip-opt input {
+ position: absolute;
+ opacity: 0;
+ width: 0;
+ height: 0;
+}
+.chip-opt span {
+ display: inline-flex;
+ align-items: center;
+ padding: 7px 14px;
+ border-radius: 999px;
+ border: 1px solid var(--line);
+ font-size: 12.5px;
+ font-weight: 500;
+ color: var(--ink-2);
+ background: var(--surface-raised);
+ transition: all 0.15s;
+}
+.chip-opt input:checked + span {
+ background: var(--ember-soft);
+ border-color: var(--ember);
+ color: var(--ember-strong);
+ font-weight: 700;
+}
+.chip-opt input:focus-visible + span {
+ outline: 2px solid var(--ember);
+ outline-offset: 1px;
}
-.chip-opt input:focus-visible + span{ outline:2px solid var(--ember); outline-offset:1px; }
/* ─── Blend cards ─────────────────────────────────────────────────────── */
-#blend-body.collapsed .blend-cards, #blend-body.collapsed .blend-total,
-#blend-body.collapsed #btn-add-blend, #blend-body.collapsed .subhead,
-#blend-body.collapsed .field.wide, #blend-body.collapsed .field-grid{ display:none; }
-.blend-cards{ display:flex; flex-direction:column; gap:10px; margin-bottom:12px; }
-.blend-card{
- display:grid; grid-template-columns:1.4fr 1fr 1fr .7fr .8fr auto; gap:10px; align-items:end;
- background:var(--surface-sunken); border-radius:var(--radius-md); padding:12px;
+#blend-body.collapsed .blend-cards,
+#blend-body.collapsed .blend-total,
+#blend-body.collapsed #btn-add-blend,
+#blend-body.collapsed .subhead,
+#blend-body.collapsed .field.wide,
+#blend-body.collapsed .field-grid {
+ display: none;
}
-.blend-card .field-label{ font-size:10.5px; }
-.blend-remove{
- background:none; border:1px solid var(--line); color:var(--ink-3); width:30px; height:30px;
- border-radius:var(--radius-sm); cursor:pointer; font-size:13px;
+.blend-cards {
+ display: flex;
+ flex-direction: column;
+ gap: 10px;
+ margin-bottom: 12px;
+}
+.blend-card {
+ display: grid;
+ grid-template-columns: 1.4fr 1fr 1fr 0.7fr 0.8fr auto;
+ gap: 10px;
+ align-items: end;
+ background: var(--surface-sunken);
+ border-radius: var(--radius-md);
+ padding: 12px;
+}
+.blend-card .field-label {
+ font-size: 10.5px;
+}
+.blend-remove {
+ background: none;
+ border: 1px solid var(--line);
+ color: var(--ink-3);
+ width: 30px;
+ height: 30px;
+ border-radius: var(--radius-sm);
+ cursor: pointer;
+ font-size: 13px;
+}
+.blend-remove:hover {
+ background: var(--fail-bg);
+ color: var(--fail);
+ border-color: var(--fail);
+}
+.blend-total {
+ display: flex;
+ align-items: center;
+ gap: 10px;
+ margin-bottom: 14px;
+}
+.blend-total-bar {
+ flex: 1 1 auto;
+ height: 6px;
+ border-radius: 999px;
+ background: var(--surface-sunken);
+ overflow: hidden;
+}
+.blend-total-fill {
+ height: 100%;
+ background: var(--ember);
+ width: 0%;
+ transition:
+ width 0.2s,
+ background 0.2s;
+}
+.blend-total-fill.over,
+.blend-total-fill.under {
+ background: var(--fail);
+}
+.blend-total-label {
+ font-size: 11.5px;
+ font-family: var(--font-mono);
+ color: var(--ink-3);
+ white-space: nowrap;
+}
+@media (max-width: 640px) {
+ .blend-card {
+ grid-template-columns: 1fr 1fr;
+ }
}
-.blend-remove:hover{ background:var(--fail-bg); color:var(--fail); border-color:var(--fail); }
-.blend-total{ display:flex; align-items:center; gap:10px; margin-bottom:14px; }
-.blend-total-bar{ flex:1 1 auto; height:6px; border-radius:999px; background:var(--surface-sunken); overflow:hidden; }
-.blend-total-fill{ height:100%; background:var(--ember); width:0%; transition:width .2s,background .2s; }
-.blend-total-fill.over, .blend-total-fill.under{ background:var(--fail); }
-.blend-total-label{ font-size:11.5px; font-family:var(--font-mono); color:var(--ink-3); white-space:nowrap; }
-@media (max-width:640px){ .blend-card{ grid-template-columns:1fr 1fr; } }
/* ─── Milestone lists (temps / roast log) ────────────────────────────── */
-.milestone-list{ display:flex; flex-direction:column; gap:6px; }
-.milestone-row{
- display:grid; grid-template-columns:110px 64px 1fr 90px; gap:12px; align-items:center;
- padding:8px 4px; border-bottom:1px solid var(--line);
+.milestone-list {
+ display: flex;
+ flex-direction: column;
+ gap: 6px;
}
-.milestone-row:last-child{ border-bottom:none; }
-.milestone-row.log-row{ grid-template-columns:110px 64px 72px 64px 1fr; }
-.milestone-label{ font-size:13px; font-weight:600; color:var(--ink); }
-.milestone-plan{
- font-family:var(--font-mono); font-size:13px; color:var(--ink-2); text-align:center;
- background:var(--surface-sunken); border-radius:var(--radius-sm); padding:6px 4px;
+.milestone-row {
+ display: grid;
+ grid-template-columns: 110px 64px 1fr 90px;
+ gap: 12px;
+ align-items: center;
+ padding: 8px 4px;
+ border-bottom: 1px solid var(--line);
}
-.milestone-time{ text-align:center; }
-.band-track{
- position:relative; height:6px; border-radius:999px; background:var(--surface-sunken);
+.milestone-row:last-child {
+ border-bottom: none;
}
-.band-range{ position:absolute; top:0; bottom:0; background:var(--pass-bg); border-radius:999px; }
-.band-marker{
- position:absolute; top:50%; width:10px; height:10px; border-radius:50%;
- background:var(--ink); border:2px solid var(--surface-raised); box-shadow:0 0 0 1px var(--ink-3);
- transform:translate(-50%,-50%); display:none; transition:left .15s;
+.milestone-row.log-row {
+ grid-template-columns: 110px 64px 72px 64px 1fr;
}
-.band-marker.out-of-band{ background:var(--fail); box-shadow:0 0 0 1px var(--fail); }
-@media (max-width:640px){
- .milestone-row, .milestone-row.log-row{ grid-template-columns:1fr; gap:6px; }
- .band-track{ order:3; }
+.milestone-label {
+ font-size: 13px;
+ font-weight: 600;
+ color: var(--ink);
+}
+.milestone-plan {
+ font-family: var(--font-mono);
+ font-size: 13px;
+ color: var(--ink-2);
+ text-align: center;
+ background: var(--surface-sunken);
+ border-radius: var(--radius-sm);
+ padding: 6px 4px;
+}
+.milestone-time {
+ text-align: center;
+}
+.band-track {
+ position: relative;
+ height: 6px;
+ border-radius: 999px;
+ background: var(--surface-sunken);
+}
+.band-range {
+ position: absolute;
+ top: 0;
+ bottom: 0;
+ background: var(--pass-bg);
+ border-radius: 999px;
+}
+.band-marker {
+ position: absolute;
+ top: 50%;
+ width: 10px;
+ height: 10px;
+ border-radius: 50%;
+ background: var(--ink);
+ border: 2px solid var(--surface-raised);
+ box-shadow: 0 0 0 1px var(--ink-3);
+ transform: translate(-50%, -50%);
+ display: none;
+ transition: left 0.15s;
+}
+.band-marker.out-of-band {
+ background: var(--fail);
+ box-shadow: 0 0 0 1px var(--fail);
+}
+@media (max-width: 640px) {
+ .milestone-row,
+ .milestone-row.log-row {
+ grid-template-columns: 1fr;
+ gap: 6px;
+ }
+ .band-track {
+ order: 3;
+ }
}
/* ─── Actuator timeline ───────────────────────────────────────────────── */
-.actuator-timeline{ display:flex; flex-direction:column; }
-.actuator-step{ display:flex; gap:14px; position:relative; padding-bottom:16px; }
-.actuator-step:last-child{ padding-bottom:0; }
-.actuator-rail{ display:flex; flex-direction:column; align-items:center; flex:0 0 auto; }
-.actuator-dot{
- width:10px; height:10px; border-radius:50%; background:var(--ember); margin-top:10px; flex:0 0 auto;
+.actuator-timeline {
+ display: flex;
+ flex-direction: column;
}
-.actuator-line{ width:1px; flex:1 1 auto; background:var(--line); margin-top:4px; }
-.actuator-step:last-child .actuator-line{ display:none; }
-.actuator-card{
- flex:1 1 auto; background:var(--surface-sunken); border-radius:var(--radius-md); padding:12px 14px;
- display:grid; grid-template-columns:70px 1fr 1fr auto; gap:10px; align-items:end;
+.actuator-step {
+ display: flex;
+ gap: 14px;
+ position: relative;
+ padding-bottom: 16px;
}
-.actuator-card .field-label{ font-size:10.5px; }
-.actuator-why{ grid-column:1 / -1; }
-.actuator-remove{
- background:none; border:1px solid var(--line); color:var(--ink-3); width:28px; height:28px;
- border-radius:var(--radius-sm); cursor:pointer; font-size:12px; align-self:start;
+.actuator-step:last-child {
+ padding-bottom: 0;
+}
+.actuator-rail {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ flex: 0 0 auto;
+}
+.actuator-dot {
+ width: 10px;
+ height: 10px;
+ border-radius: 50%;
+ background: var(--ember);
+ margin-top: 10px;
+ flex: 0 0 auto;
+}
+.actuator-line {
+ width: 1px;
+ flex: 1 1 auto;
+ background: var(--line);
+ margin-top: 4px;
+}
+.actuator-step:last-child .actuator-line {
+ display: none;
+}
+.actuator-card {
+ flex: 1 1 auto;
+ background: var(--surface-sunken);
+ border-radius: var(--radius-md);
+ padding: 12px 14px;
+ display: grid;
+ grid-template-columns: 70px 1fr 1fr auto;
+ gap: 10px;
+ align-items: end;
+}
+.actuator-card .field-label {
+ font-size: 10.5px;
+}
+.actuator-why {
+ grid-column: 1 / -1;
+}
+.actuator-remove {
+ background: none;
+ border: 1px solid var(--line);
+ color: var(--ink-3);
+ width: 28px;
+ height: 28px;
+ border-radius: var(--radius-sm);
+ cursor: pointer;
+ font-size: 12px;
+ align-self: start;
+}
+.actuator-remove:hover {
+ background: var(--fail-bg);
+ color: var(--fail);
+ border-color: var(--fail);
+}
+@media (max-width: 640px) {
+ .actuator-card {
+ grid-template-columns: 1fr 1fr;
+ }
}
-.actuator-remove:hover{ background:var(--fail-bg); color:var(--fail); border-color:var(--fail); }
-@media (max-width:640px){ .actuator-card{ grid-template-columns:1fr 1fr; } }
/* ─── Dock: shared card chrome ───────────────────────────────────────── */
-.dock-card{
- background:var(--surface-raised); border:1px solid var(--line); border-radius:var(--radius-lg);
- box-shadow:var(--shadow-card); padding:18px 20px;
+.dock-card {
+ background: var(--surface-raised);
+ border: 1px solid var(--line);
+ border-radius: var(--radius-lg);
+ box-shadow: var(--shadow-card);
+ padding: 18px 20px;
+}
+.dock-card-head {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ margin-bottom: 12px;
+}
+.dock-card-head h2 {
+ font-size: 13px;
+ font-weight: 700;
+ text-transform: uppercase;
+ letter-spacing: 0.05em;
+ color: var(--ink-2);
}
-.dock-card-head{ display:flex; align-items:center; justify-content:space-between; margin-bottom:12px; }
-.dock-card-head h2{ font-size:13px; font-weight:700; text-transform:uppercase; letter-spacing:.05em; color:var(--ink-2); }
/* ─── Ledger ──────────────────────────────────────────────────────────── */
-.ledger-group{ display:flex; flex-direction:column; }
-.ledger-row{ display:flex; align-items:center; gap:8px; padding:6px 0; border-bottom:1px solid var(--line); }
-.ledger-row:last-child{ border-bottom:none; }
-.l-fid{ font-family:var(--font-mono); font-size:9.5px; color:var(--ink-3); background:var(--surface-sunken); border-radius:4px; padding:1px 4px; flex:0 0 auto; }
-.l-label{ font-size:12.5px; color:var(--ink-2); flex:1 1 auto; }
-.l-val{ font-family:var(--font-mono); font-size:13px; font-weight:600; color:var(--ink); text-align:right; min-width:52px; }
-.ledger-input{
- width:60px; text-align:right; font-family:var(--font-mono); font-size:13px; font-weight:600;
- padding:4px 7px; border:1px solid var(--line); border-radius:var(--radius-sm); background:var(--surface-sunken); color:var(--ink);
+.ledger-group {
+ display: flex;
+ flex-direction: column;
}
-.ledger-input:focus{ outline:none; border-color:var(--ember); box-shadow:0 0 0 3px var(--ember-soft); background:var(--surface-raised); }
-.ledger-total{
- display:flex; align-items:baseline; justify-content:space-between;
- margin:10px 0; padding-top:8px; border-top:1.5px solid var(--ink);
+.ledger-row {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ padding: 6px 0;
+ border-bottom: 1px solid var(--line);
+}
+.ledger-row:last-child {
+ border-bottom: none;
+}
+.l-fid {
+ font-family: var(--font-mono);
+ font-size: 9.5px;
+ color: var(--ink-3);
+ background: var(--surface-sunken);
+ border-radius: 4px;
+ padding: 1px 4px;
+ flex: 0 0 auto;
+}
+.l-label {
+ font-size: 12.5px;
+ color: var(--ink-2);
+ flex: 1 1 auto;
+}
+.l-val {
+ font-family: var(--font-mono);
+ font-size: 13px;
+ font-weight: 600;
+ color: var(--ink);
+ text-align: right;
+ min-width: 52px;
+}
+.ledger-input {
+ width: 60px;
+ text-align: right;
+ font-family: var(--font-mono);
+ font-size: 13px;
+ font-weight: 600;
+ padding: 4px 7px;
+ border: 1px solid var(--line);
+ border-radius: var(--radius-sm);
+ background: var(--surface-sunken);
+ color: var(--ink);
+}
+.ledger-input:focus {
+ outline: none;
+ border-color: var(--ember);
+ box-shadow: 0 0 0 3px var(--ember-soft);
+ background: var(--surface-raised);
+}
+.ledger-total {
+ display: flex;
+ align-items: baseline;
+ justify-content: space-between;
+ margin: 10px 0;
+ padding-top: 8px;
+ border-top: 1.5px solid var(--ink);
+}
+.ledger-total span {
+ font-size: 12px;
+ font-weight: 700;
+ text-transform: uppercase;
+ letter-spacing: 0.04em;
+ color: var(--ink-2);
+}
+.ledger-total output {
+ font-family: var(--font-serif);
+ font-size: 26px;
+ font-weight: 600;
+ color: var(--ink);
+}
+.ledger-total.drop {
+ border-top: none;
+ margin-top: 4px;
+ padding-top: 10px;
+ background: var(--ember-soft);
+ border-radius: var(--radius-md);
+ padding: 12px 14px;
+ margin-bottom: 0;
+}
+.ledger-total.drop span {
+ color: var(--ember-strong);
+}
+.ledger-total.drop output {
+ color: var(--ember-strong);
+ font-size: 30px;
}
-.ledger-total span{ font-size:12px; font-weight:700; text-transform:uppercase; letter-spacing:.04em; color:var(--ink-2); }
-.ledger-total output{ font-family:var(--font-serif); font-size:26px; font-weight:600; color:var(--ink); }
-.ledger-total.drop{ border-top:none; margin-top:4px; padding-top:10px; background:var(--ember-soft); border-radius:var(--radius-md); padding:12px 14px; margin-bottom:0; }
-.ledger-total.drop span{ color:var(--ember-strong); }
-.ledger-total.drop output{ color:var(--ember-strong); font-size:30px; }
-.ledger-info{
- display:flex; align-items:center; gap:8px; flex-wrap:wrap; margin:10px 0 16px;
- padding:8px 10px; border-left:2px solid var(--line-strong); background:var(--surface-sunken); border-radius:0 var(--radius-sm) var(--radius-sm) 0;
+.ledger-info {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ flex-wrap: wrap;
+ margin: 10px 0 16px;
+ padding: 8px 10px;
+ border-left: 2px solid var(--line-strong);
+ background: var(--surface-sunken);
+ border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
+}
+.info-pill {
+ display: flex;
+ align-items: center;
+ gap: 5px;
+ font-size: 11.5px;
+ color: var(--ink-2);
+}
+.info-pill span {
+ color: var(--ink-3);
+}
+.info-pill output {
+ font-family: var(--font-mono);
+ font-weight: 600;
+}
+.info-note {
+ font-size: 10px;
+ color: var(--ink-3);
+ flex-basis: 100%;
}
-.info-pill{ display:flex; align-items:center; gap:5px; font-size:11.5px; color:var(--ink-2); }
-.info-pill span{ color:var(--ink-3); }
-.info-pill output{ font-family:var(--font-mono); font-weight:600; }
-.info-note{ font-size:10px; color:var(--ink-3); flex-basis:100%; }
/* ─── Sanity checks ───────────────────────────────────────────────────── */
-.checks-grid{ display:grid; grid-template-columns:1fr 1fr; gap:10px; }
-.check-tile{
- border:1px solid var(--line); border-radius:var(--radius-md); padding:10px 12px;
- display:flex; flex-direction:column; gap:2px; position:relative;
+.checks-grid {
+ display: grid;
+ grid-template-columns: 1fr 1fr;
+ gap: 10px;
}
-.check-name{ font-size:10.5px; color:var(--ink-3); font-weight:600; text-transform:uppercase; letter-spacing:.02em; }
-.check-value{ font-family:var(--font-mono); font-size:18px; font-weight:700; color:var(--ink); }
-.check-band{ font-size:10.5px; color:var(--ink-3); }
-.check-tile::before{
- content:""; position:absolute; top:10px; right:10px; width:8px; height:8px; border-radius:50%;
- background:var(--ink-3);
+.check-tile {
+ border: 1px solid var(--line);
+ border-radius: var(--radius-md);
+ padding: 10px 12px;
+ display: flex;
+ flex-direction: column;
+ gap: 2px;
+ position: relative;
+}
+.check-name {
+ font-size: 10.5px;
+ color: var(--ink-3);
+ font-weight: 600;
+ text-transform: uppercase;
+ letter-spacing: 0.02em;
+}
+.check-value {
+ font-family: var(--font-mono);
+ font-size: 18px;
+ font-weight: 700;
+ color: var(--ink);
+}
+.check-band {
+ font-size: 10.5px;
+ color: var(--ink-3);
+}
+.check-tile::before {
+ content: "";
+ position: absolute;
+ top: 10px;
+ right: 10px;
+ width: 8px;
+ height: 8px;
+ border-radius: 50%;
+ background: var(--ink-3);
+}
+.check-tile.pass::before {
+ background: var(--pass);
+}
+.check-tile.fail::before {
+ background: var(--fail);
+}
+.check-tile.pass {
+ border-color: var(--pass-bg);
+ background: var(--pass-bg);
+}
+.check-tile.fail {
+ border-color: var(--fail-bg);
+ background: var(--fail-bg);
+}
+.check-tile.pass .check-value {
+ color: var(--pass);
+}
+.check-tile.fail .check-value {
+ color: var(--fail);
}
-.check-tile.pass::before{ background:var(--pass); }
-.check-tile.fail::before{ background:var(--fail); }
-.check-tile.pass{ border-color:var(--pass-bg); background:var(--pass-bg); }
-.check-tile.fail{ border-color:var(--fail-bg); background:var(--fail-bg); }
-.check-tile.pass .check-value{ color:var(--pass); }
-.check-tile.fail .check-value{ color:var(--fail); }
/* ─── Curve card ──────────────────────────────────────────────────────── */
-.curve-legend{ display:flex; align-items:center; gap:10px; font-size:10.5px; color:var(--ink-3); text-transform:none; letter-spacing:0; font-weight:500; }
-.curve-legend .sw{ display:inline-block; width:12px; height:2px; margin-right:3px; vertical-align:middle; }
-.sw-plan{ background:var(--ink); }
-.sw-ref{ background:var(--ink-3); border-top:1px dashed var(--ink-3); background:none; height:0; border-bottom:1.5px dashed var(--ink-3); }
-.curve-wrap{ border-radius:var(--radius-md); overflow:hidden; border:1px solid var(--line); }
+.curve-legend {
+ display: flex;
+ align-items: center;
+ gap: 10px;
+ font-size: 10.5px;
+ color: var(--ink-3);
+ text-transform: none;
+ letter-spacing: 0;
+ font-weight: 500;
+}
+.curve-legend .sw {
+ display: inline-block;
+ width: 12px;
+ height: 2px;
+ margin-right: 3px;
+ vertical-align: middle;
+}
+.sw-plan {
+ background: var(--ink);
+}
+.sw-ref {
+ background: var(--ink-3);
+ border-top: 1px dashed var(--ink-3);
+ background: none;
+ height: 0;
+ border-bottom: 1.5px dashed var(--ink-3);
+}
+.curve-wrap {
+ border-radius: var(--radius-md);
+ overflow: hidden;
+ border: 1px solid var(--line);
+}
/* ─── PWA and mobile layout ───────────────────────────────────────────── */
-.connection-status{
- position:sticky; top:var(--header-h); z-index:29; padding:8px 14px;
- background:var(--warn-bg); border-bottom:1px solid #E8D49E; color:#705318;
- font-size:13px; font-weight:600; text-align:center;
+.connection-status {
+ position: sticky;
+ top: var(--header-h);
+ z-index: 29;
+ padding: 8px 14px;
+ background: var(--warn-bg);
+ border-bottom: 1px solid #e8d49e;
+ color: #705318;
+ font-size: 13px;
+ font-weight: 600;
+ text-align: center;
}
-.connection-status.hidden{ display:none; }
-
-@media (max-width:720px){
- :root{ --header-h:auto; }
- body{ font-size:16px; padding-bottom:env(safe-area-inset-bottom); }
- .app-header{
- position:sticky; padding:10px 12px; gap:10px;
- padding-top:max(10px, env(safe-area-inset-top));
- }
- .brand{ width:100%; justify-content:space-between; }
- .brand-mark{ font-size:24px; }
- .brand-text h1{ font-size:16px; }
- .brand-sub{ font-size:12px; }
- .section-nav{ width:100%; order:2; margin:0 -2px; }
- .section-nav a{ min-height:40px; display:inline-flex; align-items:center; padding:7px 12px; }
- .header-actions{
- order:3; width:100%; display:grid; grid-template-columns:repeat(3, minmax(0, 1fr)); gap:7px;
- }
- .header-divider{ display:none; }
- .ghost-btn, .primary-btn, label.filebtn{
- min-height:44px; padding:8px 6px; font-size:12px; line-height:1.15;
- text-align:center; white-space:normal;
- }
- .autosave-chip{ grid-column:1 / -1; justify-content:center; min-height:32px; margin:0; }
- .workspace-grid{ padding:14px 10px 48px; gap:14px; }
- .panel-card{ margin-bottom:14px; border-radius:12px; }
- .panel-head{ padding:14px; align-items:flex-start; }
- .panel-head h2{ font-size:16px; padding-top:4px; }
- .panel-body{ padding:14px; }
- .field-grid{ grid-template-columns:1fr; gap:12px; }
- .field-input, .text-input{ min-height:44px; font-size:16px; }
- .field-input.sm{ font-size:16px; }
- .segmented{ display:flex; width:100%; }
- .seg-opt{ flex:1 1 auto; }
- .seg-opt span{ min-height:40px; display:flex; align-items:center; justify-content:center; padding:6px 9px; text-align:center; white-space:normal; }
- .chip-group{ gap:7px; }
- .chip-opt{ flex:1 1 auto; }
- .chip-opt span{ min-height:40px; justify-content:center; width:100%; padding:7px 10px; text-align:center; }
- .blend-card{ padding:12px; gap:10px; }
- .blend-remove, .actuator-remove, .icon-btn{ min-width:44px; min-height:44px; }
- .milestone-row, .milestone-row.log-row{ padding:12px 0; }
- .milestone-plan{ min-height:40px; display:flex; align-items:center; justify-content:center; }
- .actuator-step{ gap:0; }
- .actuator-rail{ display:none; }
- .actuator-card{ padding:12px; }
- .dock-card{ padding:14px; border-radius:12px; }
- .checks-grid{ grid-template-columns:1fr; }
- .check-tile{ min-height:76px; }
- .curve-wrap{ overflow-x:auto; }
- #curve-svg-live{ min-width:520px; }
- .drawer{ width:100%; max-width:none; }
- .drawer-head{ padding:14px; }
- .drawer-body{ padding:14px; }
+.connection-status.hidden {
+ display: none;
}
-@media (prefers-reduced-motion:reduce){
- *, *::before, *::after{ animation-duration:.01ms !important; animation-iteration-count:1 !important; scroll-behavior:auto !important; transition-duration:.01ms !important; }
+@media (max-width: 720px) {
+ :root {
+ --header-h: auto;
+ }
+ body {
+ font-size: 16px;
+ padding-bottom: env(safe-area-inset-bottom);
+ }
+ .app-header {
+ position: sticky;
+ padding: 10px 12px;
+ gap: 10px;
+ padding-top: max(10px, env(safe-area-inset-top));
+ }
+ .brand {
+ width: 100%;
+ justify-content: space-between;
+ }
+ .brand-mark {
+ font-size: 24px;
+ }
+ .brand-text h1 {
+ font-size: 16px;
+ }
+ .brand-sub {
+ font-size: 12px;
+ }
+ .section-nav {
+ width: 100%;
+ order: 2;
+ margin: 0 -2px;
+ }
+ .section-nav a {
+ min-height: 40px;
+ display: inline-flex;
+ align-items: center;
+ padding: 7px 12px;
+ }
+ .header-actions {
+ order: 3;
+ width: 100%;
+ display: grid;
+ grid-template-columns: repeat(3, minmax(0, 1fr));
+ gap: 7px;
+ }
+ .header-divider {
+ display: none;
+ }
+ .ghost-btn,
+ .primary-btn,
+ label.filebtn {
+ min-height: 44px;
+ padding: 8px 6px;
+ font-size: 12px;
+ line-height: 1.15;
+ text-align: center;
+ white-space: normal;
+ }
+ .autosave-chip {
+ grid-column: 1 / -1;
+ justify-content: center;
+ min-height: 32px;
+ margin: 0;
+ }
+ .workspace-grid {
+ padding: 14px 10px 48px;
+ gap: 14px;
+ }
+ .panel-card {
+ margin-bottom: 14px;
+ border-radius: 12px;
+ }
+ .panel-head {
+ padding: 14px;
+ align-items: flex-start;
+ }
+ .panel-head h2 {
+ font-size: 16px;
+ padding-top: 4px;
+ }
+ .panel-body {
+ padding: 14px;
+ }
+ .field-grid {
+ grid-template-columns: 1fr;
+ gap: 12px;
+ }
+ .field-input,
+ .text-input {
+ min-height: 44px;
+ font-size: 16px;
+ }
+ .field-input.sm {
+ font-size: 16px;
+ }
+ .segmented {
+ display: flex;
+ width: 100%;
+ }
+ .seg-opt {
+ flex: 1 1 auto;
+ }
+ .seg-opt span {
+ min-height: 40px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ padding: 6px 9px;
+ text-align: center;
+ white-space: normal;
+ }
+ .chip-group {
+ gap: 7px;
+ }
+ .chip-opt {
+ flex: 1 1 auto;
+ }
+ .chip-opt span {
+ min-height: 40px;
+ justify-content: center;
+ width: 100%;
+ padding: 7px 10px;
+ text-align: center;
+ }
+ .blend-card {
+ padding: 12px;
+ gap: 10px;
+ }
+ .blend-remove,
+ .actuator-remove,
+ .icon-btn {
+ min-width: 44px;
+ min-height: 44px;
+ }
+ .milestone-row,
+ .milestone-row.log-row {
+ padding: 12px 0;
+ }
+ .milestone-plan {
+ min-height: 40px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ }
+ .actuator-step {
+ gap: 0;
+ }
+ .actuator-rail {
+ display: none;
+ }
+ .actuator-card {
+ padding: 12px;
+ }
+ .dock-card {
+ padding: 14px;
+ border-radius: 12px;
+ }
+ .checks-grid {
+ grid-template-columns: 1fr;
+ }
+ .check-tile {
+ min-height: 76px;
+ }
+ .curve-wrap {
+ overflow-x: auto;
+ }
+ #curve-svg-live {
+ min-width: 520px;
+ }
+ .drawer {
+ width: 100%;
+ max-width: none;
+ }
+ .drawer-head {
+ padding: 14px;
+ }
+ .drawer-body {
+ padding: 14px;
+ }
+}
+
+@media (prefers-reduced-motion: reduce) {
+ *,
+ *::before,
+ *::after {
+ animation-duration: 0.01ms !important;
+ animation-iteration-count: 1 !important;
+ scroll-behavior: auto !important;
+ transition-duration: 0.01ms !important;
+ }
}
/* ─── Print: hide the screen shell, show the paper worksheet ───────────── */
-#print-sheet{ display:none; }
-.pv{ display:none; }
+#print-sheet {
+ display: none;
+}
+.pv {
+ display: none;
+}
-@media print{
- .app-header, .drawer, .drawer-overlay, .workspace-grid{ display:none !important; }
- body{ background:#fff; }
- #print-sheet{ display:block; }
- .ws-input{ display:none !important; }
- .pv{ display:inline-block; min-width:inherit; border-bottom:.9pt solid var(--ink); }
- .opt input:checked + span{ border:.9pt solid var(--ink); background:none; color:var(--ink); border-radius:50%; padding:0 1.4mm; }
- td.passcell.pass::after, td.passcell.fail::after{ content:none; }
- td.passcell.pass::before{ content:"✓ "; }
- td.passcell.fail::before{ content:"✗ "; }
+@media print {
+ .app-header,
+ .drawer,
+ .drawer-overlay,
+ .workspace-grid {
+ display: none !important;
+ }
+ body {
+ background: #fff;
+ }
+ #print-sheet {
+ display: block;
+ }
+ .ws-input {
+ display: none !important;
+ }
+ .pv {
+ display: inline-block;
+ min-width: inherit;
+ border-bottom: 0.9pt solid var(--ink);
+ }
+ .opt input:checked + span {
+ border: 0.9pt solid var(--ink);
+ background: none;
+ color: var(--ink);
+ border-radius: 50%;
+ padding: 0 1.4mm;
+ }
+ td.passcell.pass::after,
+ td.passcell.fail::after {
+ content: none;
+ }
+ td.passcell.pass::before {
+ content: "✓ ";
+ }
+ td.passcell.fail::before {
+ content: "✗ ";
+ }
}
/* ─── Legacy .opt styling reused by the (hidden-on-screen) print worksheet's own radios ── */
-.opt{ display:inline-block; cursor:pointer; margin-right:1.5mm; }
-.opt input{ position:absolute; opacity:0; width:0; height:0; }
-.opt span{ padding:0 .8mm; border-radius:3mm; }
-.opt input:checked + span{ background:#f6efe7; border:.9pt solid #7a3b12; color:#7a3b12; font-weight:700; }
-input.f, select.f{ border:none; border-bottom:.9pt solid #1a1512; background:transparent; font:inherit; height:4.2mm; padding:0 .5mm; color:#1a1512; }
+.opt {
+ display: inline-block;
+ cursor: pointer;
+ margin-right: 1.5mm;
+}
+.opt input {
+ position: absolute;
+ opacity: 0;
+ width: 0;
+ height: 0;
+}
+.opt span {
+ padding: 0 0.8mm;
+ border-radius: 3mm;
+}
+.opt input:checked + span {
+ background: #f6efe7;
+ border: 0.9pt solid #7a3b12;
+ color: #7a3b12;
+ font-weight: 700;
+}
+input.f,
+select.f {
+ border: none;
+ border-bottom: 0.9pt solid #1a1512;
+ background: transparent;
+ font: inherit;
+ height: 4.2mm;
+ padding: 0 0.5mm;
+ color: #1a1512;
+}
diff --git a/public/index.html b/public/index.html
index 34be1c2..0ac9b6c 100644
--- a/public/index.html
+++ b/public/index.html
@@ -53,10 +53,13 @@
-
-
+
(r.ok ? r.json() : null))
.then((body) => {
- if (body?.user?.role === "admin") {
- const button = document.getElementById("btn-admin");
- button.classList.remove("hidden");
- button.onclick = () => {
- location.href = "/admin";
- };
- }
+ if (body?.user?.role === "admin")
+ document.getElementById("menu-admin").classList.remove("hidden");
})
.catch(() => {});
initPrefillPanel({