Files
onefinity-firmware/src/stylus/style.styl
Henrik Muehe 5926316a25 Fix: real-hardware bring-up issues found at 1920x1080 on the Pi
After testing the V09 redesign live on the Pi at onefinity.local
(1920x1080, Chrome fullscreen) several real bugs surfaced. This
commit fixes all of them.

Layout fits at 1920x1080
- Cap .app-shell at 100vh height with overflow:hidden so child
  flex containers actually constrain to one screen.
- Make .control-page / .program-page / .console-page use
  flex 1 1 auto + min-height 0 + overflow hidden so the page total
  no longer grows to ~36 000 px when the gcode-viewer is mounted.
- Override clusterize.css default max-height: 200px on the
  .clusterize-scroll element with max-height: none + flex 1 1 0 +
  height 100% so the gcode listing fills the available column.

E-Stop in the header
- The legacy estop.pug SVG had width=130 height=130 but no
  viewBox, so CSS-only sizing did nothing and the SVG content
  spilled ~26 px off the right edge of the screen and ~70 px
  below the header. Add viewBox="0 0 130 130" plus
  preserveAspectRatio so CSS sizing actually shrinks the inner
  geometry. Drop the octagonal clip-path (the SVG already
  carries its own yellow safety ring + EMERGENCY/STOP text).

3D toolpath preview (path-viewer)
- The legacy .path-viewer.small CSS clamped the canvas to
  340 x 150 floated into the corner. In the new program-body
  grid we want it to fill the 600 px right column. Override
  with width 100%, height auto, float none, !important.
- Make orbit.js wheel/touchstart/touchmove listeners
  {passive: false} so OrbitControls.preventDefault() actually
  works and the page no longer scrolls while panning the 3D
  view on a touch screen.

Vue 1 template + reactivity bugs exposed by the live data
- Replace v-else-if (Vue 1 has no v-else-if) in
  control-view.pug with three sibling v-if templates that
  mutually exclude on w.enabled and state['2an'] == 3.
- axis-vars._get_motor_id: guard motor.axis.toLowerCase()
  against undefined motors (initial config is [{}, {}, ...]).
- axis-vars._check_is_enabled: prefer config.motors[i].axis
  when present, fall back to state[N + 'an'] only for
  recognised axes (x/y/z/a) so undefined == undefined
  doesn't mistakenly enable b/c rows.
- program-mixin: tolerate state.files / state.gcode_list
  being undefined right after connect.

App-shell race conditions
- Skip the early parse_hash() in app.js ready() when the
  initial hash is in the settings family. Those Svelte
  components read settings.units / settings.probing-prompts /
  motion.* etc. and crash on first paint with the empty
  placeholder config. Stay on loading-view until update()
  completes and routes us in itself.

Misc
- src/static/js/ui.js: null-guard the legacy burger menu code
  (#menuLink no longer exists). Was throwing 'Cannot set
  properties of null (setting onclick)'.
- src/static/css/Audiowide.css: switch the gstatic font URL
  from http:// to https:// so it isn't blocked as mixed
  content under the home.muehe.org HTTPS proxy.
- Macro buttons: drop the default 6 px yellow border-left.
  The stripe now only appears via .has-color when
  state.macros[i].color is actually configured. Removes the
  asymmetric/lopsided look from the screenshot.

Tested live on http://10.1.10.55/ and via the HTTPS proxy at
https://onefinity.home.muehe.org/.
2026-04-30 22:24:55 +02:00

2057 lines
34 KiB
Stylus
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// =====================================================================
// V09 redesign tokens & chrome
// =====================================================================
//
// The new shell wraps everything in `.app-shell { .app-head | .app-body }`.
// Inner views use the shared tokens below for jog/macro tiles, status
// chips and segmented controls. Anything legacy that's still needed by
// settings/admin/motor/tool/io templates remains lower in this file.
$ink = #0f172a
$ink-soft = #334155
$muted = #64748b
$muted-2 = #94a3b8
$line = #e5e7eb
$line-soft = #f1f5f9
$bg = #ffffff
$body-bg = #f1f5f9
$accent = #fde047
$accent-ink = $ink
$accent-text = #0ea5e9
// Jog tile palette V09 (flat soft slate, no shadow)
$jog-bg = #3f4b63
$jog-hover = #4a5777
$jog-dir = #5b6885
$jog-dir-hov = #6a779a
$jog-ghost = #8c97ad
$jog-ghost-hov = #9ba6bb
$jog-ink = #fff
$jog-ghost-ink = $ink
body
margin 0
font-family 'Inter', system-ui, -apple-system, sans-serif
background $body-bg
color $ink
[v-cloak]
display none
tt
color #000
background #eee
padding 2px
.button-success:not([disabled])
background-color #1cb841
.button-error:not([disabled])
background-color #ca3c3c
.button-warning:not([disabled])
background-color #df7514
.button-secondary:not([disabled])
background-color #42b8dd
.button-submit:not([disabled])
background-color #add1ad
color #fff
.button-blue:not([disabled])
background-color #0078e7
color #fff
.clear
clear left
clear right
// =====================================================================
// App shell
// =====================================================================
.app-shell
display flex
flex-direction column
height 100vh // cap at viewport so children that ask for 1fr/flex:1
width 100%
overflow hidden
background $body-bg
.app-body
flex 1
min-height 0
display flex
flex-direction column
padding 18px
overflow auto // settings/motor pages can scroll inside the body
> *
flex 1 1 auto
min-height 0
.app-head
flex 0 0 96px
height 96px
display flex
align-items center
gap 18px
padding 0 24px
background $bg
border-bottom 1px solid $line
position relative
z-index 30
.brand-blk
display flex
align-items center
gap 14px
.brand-logo
width 42px
height 42px
border-radius 8px
background repeating-linear-gradient(135deg, #a7c7a3 0 6px, transparent 6px 14px)
.brand-name
font-weight 900
font-size 22px
letter-spacing -0.01em
.head-spacer
flex 1
// Underline-ribbon tabs
.tabs-host
display inline-flex
gap 0
margin-right auto
padding-left 18px
align-items stretch
height 96px
.ktab
position relative
height 96px
padding 0 26px
display inline-flex
align-items center
gap 0.55rem
background transparent
border none
text-decoration none
color $ink-soft
font-size 1.05rem
font-weight 700
cursor pointer
transition color .15s
.fa
font-size 1.1rem
color $muted-2
transition color .15s
&:hover
color $ink
.fa
color $ink-soft
&.active
color $ink
.fa
color $ink
&.active::after
content ""
position absolute
left 14px
right 14px
bottom 0
height 5px
background $accent
border-radius 5px 5px 0 0
.ktab-badge
background #fee2e2
color #991b1b
font-size 0.7rem
padding 3px 8px
border-radius 9999px
font-weight 800
line-height 1
&.active .ktab-badge
background $accent
color $accent-ink
// System pill (collapses old chip-soup)
.sys-btn
display inline-flex
align-items center
gap 0.55rem
height 54px
padding 0 1.1rem
border-radius 14px
background $line-soft
border 1px solid $line
color $ink
font-size 0.9rem
font-weight 600
cursor pointer
user-select none
&:hover
background #e2e8f0
.pip
width 9px
height 9px
border-radius 9999px
background #22c55e
.pip.amber
background #f59e0b
.pip.red
background #dc2626
.fa-chevron-down
color $muted-2
font-size 12px
&.open
background #e2e8f0
.pi-temp-warning
align-self center
margin 0 4px
color #dc2626
font-size 24px
.state-badge
display inline-flex
align-items center
gap 0.6rem
height 54px
padding 0 1.1rem
border-radius 14px
background #dcfce7
color #166534
font-weight 800
font-size 1rem
letter-spacing 0.04em
.dot
width 10px
height 10px
border-radius 9999px
background currentColor
position relative
.dot::after
content ""
position absolute
inset -3px
border-radius 9999px
border 2px solid currentColor
opacity 0.5
animation pulse-dot 1.6s ease-out infinite
&.warn
background #fef3c7
color #92400e
&.bad
background #fee2e2
color #991b1b
&.busy
background #dbeafe
color #1e40af
&.unknown
background $line-soft
color $muted
&.unknown .dot::after
display none
@keyframes pulse-dot
0%
transform scale(0.7)
opacity 0.6
100%
transform scale(2.2)
opacity 0
@media (prefers-reduced-motion: reduce)
.state-badge .dot::after
animation none
// System popover
.sys-popover
position absolute
top 96px
right 240px
width 360px
background $bg
border 1px solid $line
border-radius 14px
box-shadow 0 18px 40px rgba(15, 23, 42, 0.18)
padding 12px
z-index 40
display flex
flex-direction column
gap 10px
.sp-row
display grid
grid-template-columns 32px 1fr auto
gap 12px
align-items center
.sp-icon
width 32px
height 32px
border-radius 8px
background $line-soft
color $ink-soft
display inline-flex
align-items center
justify-content center
img
width 18px
height 18px
.fa.sp-warn
color #f59e0b
.sp-label
font-size 0.7rem
text-transform uppercase
letter-spacing 0.1em
color $muted-2
font-weight 800
.sp-val
font-size 0.95rem
color $ink
font-weight 600
.sp-act
height 36px
padding 0 12px
border-radius 8px
background $line-soft
border 1px solid $line
color $ink
font-size 0.8rem
font-weight 700
cursor pointer
text-decoration none
display inline-flex
align-items center
gap 4px
.sp-act:hover
background #e2e8f0
.video
width 100%
height 180px
border-radius 8px
background #000
overflow hidden
position relative
img
width 100%
height 100%
object-fit cover
.sp-foot
display flex
gap 8px
margin-top 4px
padding-top 10px
border-top 1px solid $line-soft
.sp-shutdown, .sp-save
flex 1
height 40px
border-radius 10px
border 1px solid $line
background $line-soft
color $ink
font-weight 700
cursor pointer
.sp-shutdown
background #fef2f2
color #991b1b
border-color #fecaca
.sp-save:not([disabled])
background $accent
color $ink
border-color $accent
.error
background red
color #fff
.warn
background orange
.success
background green
.fa
font-size 150%
.modal-mask .fa
font-size inherit
.fa.error
background inherit
color red
.fa.warn
background inherit
color orange
.fa.success
background inherit
color green
.load-on
background-color #ccffcc
color #000
@keyframes attention
50%
opacity 0.5
.attention
background-color #f5e138
color #000
animation attention 2s step-start 0s infinite
span.unit
font-size 60%
.status
color #eee
text-align center
padding 0.125em
font-weight bold
margin-bottom 0.5em
text-transform uppercase
&.connecting
color orange
&.disconnected
color red
&.connected
color green
#overlay
position fixed
top 0
left 0
width 100%
height 100%
background-color rgba(0, 0, 0, 0.7)
z-index 2000
color white
font-weight bold
font-size 24pt
text-align center
text-transform uppercase
span
position relative
top 50%
// Form rules used by the settings/admin/motor/tool/io templates that
// still rely on Pure form classes.
.app-body .pure-control-group
label.units
width 6em
text-align left
textarea
width 24em
height 12em
> select, > input:not([type=checkbox])
min-width 300px
> tt
min-width 15.25em
padding 0.7em 1em
border-radius 3px
display inline-block
@keyframes blink
50%
fill #ff9d00
// E-Stop in the header wraps the legacy <estop> SVG component.
// Sized to fit the 96px header with breathing room. The SVG carries
// its own yellow safety ring and EMERGENCY/STOP text; we only frame
// it with a soft drop shadow and a hover/active hit target.
.app-head .estop
width 80px
height 80px
display inline-flex
align-items center
justify-content center
border-radius 9999px
cursor pointer
transition transform 0.06s, filter 0.15s
flex 0 0 auto
// Make sure the SVG's internal coordinate space scales correctly
overflow visible
&:hover
filter brightness(1.05)
&:active
transform scale(0.96)
svg
width 80px
height 80px
cursor pointer
display block
.button:hover
filter brightness(120%)
.app-head .estop.active .ring
animation blink 2s step-start 0s infinite
.app-head .estop:hover .button circle
fill #b72424 !important
#macros
width 104%
.warning-box
display flex
background-color #F3FF00
border-radius 5px
border 0
margin-bottom 10px
margin-right 130px
margin-top 10px
align-items center
justify-content center
.new-gcode
height 13rem
width 23rem
resize none
border-radius 10px
padding 20px
resize none
.flex-row-container
display flex
flex-direction row
width 710px
margin-bottom 1rem
.tabs
margin-top 5px
width 850px
padding 20px
.macros-view
padding 30px
width 95%
.macros-tab-content
padding-bottom 20px
border-radius 5px
.macros-form
padding-left 30px
.config-button
height 40px
width 150px
font-weight normal
border-radius 3px
border 0
margin-right 10px
display flex
align-items center
justify-content space-around
.submit-macros
height 50px
width 140px
color #000
margin-top 30px
font-weight normal
border 0
.path-viewer
table
margin 0.25em
width 100%
.path-viewer-toolbar
> *
margin 0.25em
.tool-button
display inline-block
cursor pointer
border 2px solid transparent
border-radius 2px
text-align center
&:hover
opacity 0.7
border 2px inset #eee
&.active
border 2px inset #888
background #ddd
img
max-height 32px
vertical-align bottom
.fa
font-size 28px
display inline-block
width 32px
.path-viewer-messages
margin 0.125em 0
th, td
padding 0.125em
&.level
text-transform capitalize
.path-viewer-content
background-color #333
background linear-gradient(to bottom, #666 0%, #222 100%);
margin-bottom 0.5em
&.small
.path-viewer-content
width 340px
height 150px
float right
margin-top -88px
.console
.console-wrapper
max-height 400px
overflow-y auto
.message
white-space pre
table
width 100%
margin 0.5em 0
border-collapse collapse
td, th
border 1px solid #ddd
padding 2px
&:first-child
border-left 0
&:last-child
border-right 0
tr
> td
margin 0 0.125em
background-color #fff
tr.log-error td
color red
tr.log-warning td
color orange
tr.log-debug td
color green
.indicators
padding 1em 0
text-align center
table
display inline-block
vertical-align top
margin 0.5em
empty-cells show
border 3px solid #bbb
td, th
padding 4px
white-space nowrap
tr:nth-child(odd)
background #f7f7f7
th
text-align left
td
text-align right
&.inputs, &.outputs
td:nth-child(1), td:nth-child(5)
text-align center
th.header
height 2.5em
border-bottom 3px solid #ccc
text-align center
th.separator
background #ccc
border 1px solid #ccc
padding 1px
&.motor_fault
td, th
text-align center
min-width 1.75em
.fa-eraser
cursor pointer
&:hover
opacity 0.5
.io
&.active
color green
&.inactive
color black
&.warn
background-color transparent
color orange
tt.save
display inline-block
border-radius 2px
background #1cb841
color rgba(0, 0, 0, 0.8)
padding 0.25em
line-height initial
.modbus-program button
margin 0.25em 0
.pure-form .modbus-regs
input, select
border none
box-shadow none
border-radius 0
background transparent
padding 0 0.5em
height 1.75em
line-height 1.75em
input
text-align right
width 6em
button
margin 2px
th, td
border 1px solid #ccc
line-height 1.75em
th
padding 0.5em
&.fixed-regs td, td.reg-index, td.modbus-status
padding 0 0.5em
td.reg-index, td.reg-addr, td.reg-value
text-align right
tr:nth-child(even):not(.warn)
background-color #f3f3f3
// Legacy `.tabs` selector retained only for #macros (Settings Macros)
// which uses .tabs as a content container with a <select> inside; the
// old radio-based tab system has been removed.
#macros .tabs
clear both
.motor.slave
.tmpl-input-axis .units::after
content "(slave motor)"
white-space nowrap
fieldset.limits, fieldset.homing, fieldset.motion .pure-control-group,
fieldset.power .pure-control-group.tmpl-input-enabled
display none
fieldset.motion .pure-control-group.tmpl-input-reverse
display inherit
.admin-general-view, .admin-network-view
h2:not(:first-of-type)
margin-top 2em
a
text-decoration none
.tip
font-style italic
font-size 90%
line-height 1.5
white-space pre-line
.modal-mask
position fixed
z-index 9998
top 0
left 0
width 100%
height 100%
background-color rgba(0, 0, 0, .25)
display table
transition opacity .3s ease
.modal-wrapper
display table-cell
vertical-align middle
.modal-container
width 380px
margin 0px auto
padding 20px 30px
background-color #fff
border-radius 2px
box-shadow 0 2px 8px rgba(0, 0, 0, .33)
transition all .3s ease
font-family Helvetica, Arial, sans-serif
.modal-header
text-decoration underline
.modal-footer
text-align right
.footer
width 100%
display flex
justify-content center
.modal-enter, .modal-leave
opacity 0
.modal-enter .modal-container
transform scale(1.1)
.modal-leave .modal-container
transform scale(0.9)
.file-upload
display none
.error-message
&.modal-mask .modal-wrapper .modal-container
width auto
max-width 800px
.modal-header h3
white-space nowrap
overflow hidden
text-overflow ellipsis
.estop
float right
transform scale(0.75)
margin-top -30px
.console
margin-bottom 1em
clear both
.wifi-confirm table
th
text-align right
th, td
padding 0 4px
.cheat-sheet
table
border-collapse collapse
margin-bottom 0.5em
*
text-align left
th, td
border 1px solid #eee
padding 4px
tr.header-row
background #eee
tr:nth-child(even)
background #f7f7f7
tr.unimplemented
background #ffff9b
tr.spacer-row
background transparent
th, td
border none
height 1em
// Compact-width fallback (e.g. 1366×768) stack the right column
// under the jog grid and tighten the macro row.
@media only screen and (max-width: 1820px)
.control-page .control-grid
grid-template-columns 1fr
.control-page .right-col
grid-template-rows auto auto
.control-page .macro-row
grid-template-columns repeat(4, 1fr)
.reset-variants
padding-left 40px
padding-bottom 20px
display grid
grid-template-rows repeat(4, auto)
grid-template-columns min-content auto
grid-gap 20px 10px
input[type="radio"]
width 30px
height 30px
label
font-size 16pt
align-self center
.pure-form-aligned .pure-control-group label:not(.extra)
width 12em
.pure-form-aligned .pure-control-group label.extra
width 8em
input.input-name
width 300px
height 40px
border-top-right-radius 8px
border-bottom-right-radius 8px
border-top-left-radius 5px
border-bottom-left-radius 5px
border-width 1px
border-color #434242
padding-left 10px
margin-left 2px
.input-container
display flex
height 50px
align-items center
p.title
font-size 20px
padding-top 20px
font-weight 600
input.input-color
height 45px
width 45px
border 1px solid #fdfdfd
border-top-left-radius 8px
border-bottom-left-radius 8px
button
border-radius 8px
border-width 1px
border 1
.input-field
margin-top 10px
select .heading-option
font-weight bold
background-color #f0f0f0
color #555
// =====================================================================
// CONTROL page (V09)
// =====================================================================
.control-page
flex 1 1 auto
min-height 0
display flex
flex-direction column
gap 14px
overflow hidden
.control-page .control-grid
display grid
grid-template-columns 720px 1fr
gap 18px
flex 1
min-height 0
// Card primitive
.control-page .jog-card
.control-page .dro-card
.control-page .stat-card
.program-page .program-card
.console-page .console-card
background $bg
border 1px solid $line
border-radius 18px
.control-page .jog-card
display flex
flex-direction column
padding 18px
min-height 0
.control-page .jog-head
display flex
align-items center
justify-content space-between
margin-bottom 14px
.control-page .jog-title
font-size 18px
font-weight 700
color $ink
.step-pre
color $muted
.step
color $accent-text
font-family 'JetBrains Mono', monospace
font-weight 700
margin-left 4px
.unit
color $muted-2
font-size 0.85em
margin-left 2px
// Step segmented control
.step-seg
display inline-flex
background $line-soft
border 1px solid $line
border-radius 14px
padding 4px
button
height 48px
min-width 64px
padding 0 1rem
border-radius 11px
font-size 1rem
font-weight 800
color $ink-soft
background transparent
border none
cursor pointer
button.active
background $ink
color $accent
// Jog grid
.control-page .jog-grid
display grid
grid-template-columns repeat(4, 1fr)
grid-template-rows repeat(4, 1fr)
gap 10px
flex 1
min-height 0
.jbtn
border-radius 16px
display flex
flex-direction column
align-items center
justify-content center
gap 4px
user-select none
-webkit-tap-highlight-color transparent
cursor pointer
font-weight 700
font-size 1.05rem
border none
background $jog-bg
color $jog-ink
transition transform 0.06s, background 0.15s
min-height 0
min-width 0
.ico
font-size 1.6rem
.lbl
font-size 0.8rem
color inherit
opacity 0.85
font-weight 600
&:hover:not([disabled])
background $jog-hover
&:active:not([disabled])
transform scale(0.97)
&[disabled]
opacity 0.45
cursor not-allowed
&.dir
background $jog-dir
&.dir:hover:not([disabled])
background $jog-dir-hov
&.ghost
background $jog-ghost
color $jog-ghost-ink
&.ghost:hover:not([disabled])
background $jog-ghost-hov
// DRO + status
.control-page .right-col
display grid
grid-template-rows 1fr 158px
gap 18px
min-height 0
.control-page .dro-card
overflow hidden
display flex
flex-direction column
.control-page .dro-head, .control-page .dro-row
display grid
grid-template-columns 84px 1.4fr 1fr 1fr 170px 170px 280px
column-gap 0.75rem
align-items center
padding 14px 22px
.control-page .dro-head
background #f8fafc
border-bottom 1px solid $line
font-size 0.78rem
font-weight 800
text-transform uppercase
letter-spacing 0.1em
color $muted-2
.control-page .dro-row
border-bottom 1px solid $line-soft
flex 1
min-height 0
&:last-child
border-bottom none
.control-page .dro-row.warn
background rgba(254, 243, 199, 0.4)
.control-page .dro-row.error
background rgba(254, 226, 226, 0.4)
.dro-axis
font-weight 900
font-size 46px
line-height 1
text-transform uppercase
.dro-axis.axis-x
color #dc2626
.dro-axis.axis-y
color #16a34a
.dro-axis.axis-z
color #2563eb
.dro-axis.axis-a
color #ea580c
.dro-axis.axis-b
color #06b6d4
.dro-axis.axis-c
color #d946ef
.dro-axis.axis-w
color #7c3aed
.dro-pos
font-family 'JetBrains Mono', monospace
font-size 36px
font-weight 800
letter-spacing -0.01em
.dro-pos .u
font-size 14px
color $muted-2
font-weight 500
margin-left 6px
.dro-sec
font-family 'JetBrains Mono', monospace
font-size 18px
color $muted
font-weight 600
// Status chips
.chip
display inline-flex
align-items center
gap 0.4rem
padding 0.4rem 0.7rem
border-radius 9999px
font-size 0.78rem
font-weight 700
.chip-green
background #dcfce7
color #166534
.chip-amber
background #fef3c7
color #92400e
.chip-red
background #fee2e2
color #991b1b
.chip-slate
background #e2e8f0
color #334155
.chip-blue
background #dbeafe
color #1e40af
// Per-axis action buttons
.icon-btn
width 72px
height 72px
border-radius 14px
display inline-flex
align-items center
justify-content center
color $ink-soft
background $line-soft
border 1px solid $line
font-size 1.45rem
cursor pointer
&:hover:not([disabled])
background #e2e8f0
&[disabled]
opacity 0.45
cursor not-allowed
.actions-cell
display flex
justify-content flex-end
gap 10px
// Status strip
.control-page .status-strip
display grid
grid-template-columns repeat(4, 1fr)
gap 18px
min-height 0
.control-page .stat-card
padding 18px 22px
display flex
flex-direction column
justify-content center
position relative
.stat-label
font-size 11px
font-weight 800
text-transform uppercase
letter-spacing 0.14em
color $muted-2
.stat-val
font-family 'JetBrains Mono', monospace
font-size 30px
font-weight 800
margin-top 6px
color $ink
.stat-val.ok
color #166534
.stat-val.warn
color #92400e
.stat-val.bad
color #991b1b
.stat-val.busy
color #1e40af
.stat-sub
font-size 13px
color $muted
margin-top 2px
.control-page .stat-tappable
cursor pointer
transition border-color 0.15s
&:hover
border-color $accent-text
.tap-hint
margin-left 6px
color $muted-2
font-size 14px
&.open
border-color $accent
box-shadow 0 0 0 3px rgba(253, 224, 71, 0.35)
// Macro row
.control-page .macro-row
display grid
grid-template-columns repeat(8, 1fr)
gap 12px
flex 0 0 auto
.macro-btn
height 84px
border-radius 14px
border 1px solid transparent
color #fff
background $jog-bg
font-weight 800
font-size 1rem
display flex
align-items center
justify-content center
gap 0.6rem
cursor pointer
overflow hidden
text-shadow 0 0 3px rgba(0, 0, 0, 0.6)
transition transform 0.06s, background 0.15s
&:hover:not([disabled])
background $jog-hover
&:active:not([disabled])
transform translateY(2px)
&[disabled]
opacity 0.45
cursor not-allowed
// Per-macro color stripe is opt-in via :class="has-color" set by
// the template only when state.macros[i].color is configured.
&.has-color
border-left-width 6px
border-left-style solid
.mnum
display inline-flex
align-items center
justify-content center
width 28px
height 28px
border-radius 8px
background $accent
color $accent-ink
font-size 0.85rem
font-weight 900
text-shadow none
flex 0 0 auto
.mname
white-space nowrap
overflow hidden
text-overflow ellipsis
// Override drawer
.override-drawer
position fixed
left 18px
right 18px
bottom 0
height 0
background $bg
border 1px solid $line
border-bottom none
border-radius 18px 18px 0 0
box-shadow 0 -10px 30px rgba(15, 23, 42, 0.18)
overflow hidden
transition height 0.2s, padding 0.2s
z-index 60
padding 0 22px
&.open
height 220px
padding 18px 22px
.override-drawer .od-head
display flex
align-items center
justify-content space-between
margin-bottom 14px
.override-drawer .od-title
font-size 1.1rem
font-weight 800
color $ink
.override-drawer .od-close
width 40px
height 40px
border-radius 10px
background $line-soft
border 1px solid $line
font-size 1.2rem
cursor pointer
.override-drawer .od-row
display grid
grid-template-columns 90px 1fr 80px 140px
gap 14px
align-items center
margin-bottom 10px
label
font-weight 700
color $ink-soft
input[type="range"]
width 100%
height 36px
.od-val
font-family 'JetBrains Mono', monospace
font-weight 700
text-align right
.override-drawer .od-reset
height 40px
padding 0 12px
border-radius 10px
background $line-soft
border 1px solid $line
color $ink
font-weight 700
cursor pointer
&:hover
background #e2e8f0
// =====================================================================
// PROGRAM page (V09)
// =====================================================================
.program-page
flex 1 1 auto
min-height 0
display flex
flex-direction column
overflow hidden
.program-card
flex 1
display flex
flex-direction column
min-height 0
overflow hidden
background $bg
border 1px solid $line
border-radius 18px
.action-bar
display flex
align-items center
gap 12px
padding 18px
flex-wrap wrap
border-bottom 1px solid $line-soft
.action-btn
height 84px
padding 0 22px
border-radius 14px
background $jog-bg
color #fff
border none
cursor pointer
display inline-flex
flex-direction column
align-items center
justify-content center
gap 4px
font-weight 800
font-size 0.9rem
letter-spacing 0.04em
transition background 0.15s, transform 0.06s
&:hover:not([disabled])
background $jog-hover
&:active:not([disabled])
transform translateY(2px)
&[disabled]
opacity 0.45
cursor not-allowed
.ico
font-size 1.4rem
&.run
background #16a34a
&.run:hover:not([disabled])
background #15803d
&.stop
background $ink
&.stop:hover:not([disabled])
background #1e293b
&.danger
background #fee2e2
color #7f1d1d
&.danger:hover:not([disabled])
background #fecaca
&.danger .ico
color #dc2626
.file-bar
display flex
align-items center
gap 10px
padding 14px 18px
flex-wrap wrap
border-bottom 1px solid $line-soft
.file-btn
height 54px
padding 0 18px
border-radius 12px
background $line-soft
border 1px solid $line
font-weight 700
color $ink
font-size 0.9rem
display inline-flex
align-items center
gap 0.4rem
cursor pointer
&:hover:not([disabled])
background #e2e8f0
&[disabled]
opacity 0.45
cursor not-allowed
.file-select
height 54px
padding 0 16px
border-radius 12px
background $bg
border 1px solid $line
font-weight 600
color $ink
font-size 0.9rem
cursor pointer
&.primary
border 2px solid $accent-text
flex 1
min-width 300px
.program-body
flex 1 1 auto
display grid
grid-template-columns 1fr 600px
min-height 0
overflow hidden
> .gcode
border-right 1px solid $line-soft
background #fafafa
padding 0
margin 0
overflow hidden
min-height 0
display flex
flex-direction column
// 3D toolpath preview fill the entire 600px column. Override the
// legacy `.path-viewer.small` rule which would clamp the canvas to
// 340x150 and float it into the corner.
> .path-viewer
overflow hidden
min-height 0
display flex
flex-direction column
.path-viewer-content
flex 1 1 auto
width 100% !important
height auto !important
min-height 0
float none !important
margin 0 !important
&.small .path-viewer-content
width 100% !important
height auto !important
float none !important
margin 0 !important
.progress-bar
height 28px
background #fff
border-top 1px solid $line-soft
position relative
> div
height 28px
background #f2ac45
color $ink
text-align center
line-height 28px
font-weight 700
// Restored layout for the program-page gcode-viewer (uses clusterize.js)
.program-body .gcode
font-family 'JetBrains Mono', monospace
font-size 13px
line-height 1.55
.clusterize
flex 1 1 0
min-height 0
overflow hidden
display flex
flex-direction column
height 100%
.clusterize-scroll
flex 1 1 0
min-height 0
height 100%
max-height none // override clusterize.css default of 200px
width 100%
overflow auto
ul
margin 0
padding 0
list-style none
li
line-height 18px
padding 1px 18px
li:nth-child(even)
background #f4f4f5
li.highlight
background #dbeafe
li > b
font-weight normal
color #f59e0b
min-width 4em
display inline-block
padding 0 0.25em
// =====================================================================
// CONSOLE page (V09)
// =====================================================================
.console-page
flex 1 1 auto
display flex
min-height 0
overflow hidden
.console-card
flex 1
display flex
flex-direction column
min-height 0
overflow hidden
background $bg
border 1px solid $line
border-radius 18px
.console-card .ptab-bar
display flex
align-items center
gap 6px
border-bottom 1px solid $line
flex 0 0 auto
padding 0 18px
background $bg
.ptab
height 60px
padding 0 22px
font-weight 700
color $muted
border-bottom 3px solid transparent
font-size 1rem
display inline-flex
align-items center
gap 0.4rem
background transparent
border-top none
border-left none
border-right none
cursor pointer
&:hover
color $ink
&.active
color $ink
border-bottom-color $ink
.ptab-badge
background $accent
color $accent-ink
font-size 0.7rem
padding 2px 7px
border-radius 9999px
font-weight 900
.mdi-pane
flex 1
min-height 0
padding 18px
display flex
flex-direction column
gap 14px
.mdi-input
display flex
align-items center
gap 0.6rem
background #0b1220
color #86efac
border 1px solid #1e293b
border-radius 14px
padding 18px 22px
font-family 'JetBrains Mono', monospace
font-size 1.3rem
font-weight 600
.prompt
color #475569
input
flex 1
background transparent
border none
color inherit
font-family inherit
font-size inherit
outline none
.mdi-send
height 48px
padding 0 18px
border-radius 10px
background #16a34a
color #fff
border none
font-weight 800
cursor pointer
font-size 0.95rem
letter-spacing 0.05em
.mdi-send[disabled]
opacity 0.45
cursor not-allowed
.mdi-keys
display grid
grid-template-columns repeat(8, 1fr)
gap 8px
flex 0 0 auto
.mkey
height 64px
border-radius 12px
background $bg
border 1px solid $line
font-weight 800
font-size 1.05rem
color $ink
cursor pointer
font-family 'JetBrains Mono', monospace
&:hover
background $line-soft
.mkey.send
background #16a34a
color #fff
border-color #15803d
grid-column span 2
font-family 'Inter', sans-serif
.mkey.send[disabled]
opacity 0.45
cursor not-allowed
.mkey.clear
background #fee2e2
color #7f1d1d
border-color #fca5a5
font-family 'Inter', sans-serif
.mdi-history
flex 1
background $bg
border 1px solid $line
border-radius 14px
padding 12px 18px
overflow auto
font-family 'JetBrains Mono', monospace
font-size 0.95rem
.mdi-empty
color $muted-2
.h-row
display grid
grid-template-columns 1fr auto
gap 14px
padding 6px 0
border-bottom 1px solid $line-soft
align-items center
cursor pointer
&:last-child
border-bottom none
.h-cmd
color $ink
font-weight 700
.h-status
color $muted-2
.messages-pane
flex 1
min-height 0
padding 18px
display flex
flex-direction column
gap 12px
overflow auto
.msg-empty
color $muted
text-align center
padding 40px
.msg
background $bg
border 1px solid $line
border-radius 14px
padding 18px 22px
display grid
grid-template-columns 54px 1fr
gap 18px
align-items flex-start
.msg.warn
border-left 6px solid #f59e0b
.msg.warn .mi
background #fef3c7
color #92400e
.msg.info
border-left 6px solid #0ea5e9
.msg.info .mi
background #dbeafe
color #1e40af
.msg .mi
width 54px
height 54px
border-radius 12px
display inline-flex
align-items center
justify-content center
font-size 1.4rem
.msg .mtitle
font-weight 800
font-size 1.05rem
color $ink
.msg .mtime
font-size 0.8rem
color $muted-2
margin-top 2px
.indicators-pane
flex 1
min-height 0
padding 18px
overflow auto
// =====================================================================
// SETTINGS shell
// =====================================================================
.settings-shell
flex 1
display grid
grid-template-columns 280px 1fr
gap 14px
min-height 0
.settings-rail
background $bg
border 1px solid $line
border-radius 14px
padding 10px
display flex
flex-direction column
gap 4px
align-self start
height fit-content
position sticky
top 18px
.set-item
height 48px
padding 0 14px
border-radius 10px
display flex
align-items center
gap 0.6rem
color $ink-soft
font-weight 700
cursor pointer
text-decoration none
font-size 0.95rem
.fa
width 18px
text-align center
color $muted-2
.set-item:hover
background $line-soft
.set-item.active
background $ink
color #fff
.fa
color $accent
.set-section
margin 8px 4px 4px
font-size 0.7rem
text-transform uppercase
letter-spacing 0.12em
color $muted-2
font-weight 800
.set-rail-foot
display flex
flex-direction column
gap 6px
margin-top 6px
padding-top 8px
border-top 1px solid $line-soft
.sp-shutdown, .sp-save
height 40px
border-radius 10px
border 1px solid $line
background $line-soft
color $ink
font-weight 700
cursor pointer
.sp-shutdown
background #fef2f2
color #991b1b
border-color #fecaca
.sp-save:not([disabled])
background $accent
color $ink
border-color $accent
.settings-content
background $bg
border 1px solid $line
border-radius 14px
padding 18px
min-height 0
overflow auto
h1, h2, h3
margin-top 0