diff --git a/fusion_plating/fusion_plating_shopfloor/__manifest__.py b/fusion_plating/fusion_plating_shopfloor/__manifest__.py
index 5a15b971..0a3c7b4e 100644
--- a/fusion_plating/fusion_plating_shopfloor/__manifest__.py
+++ b/fusion_plating/fusion_plating_shopfloor/__manifest__.py
@@ -5,7 +5,7 @@
{
'name': 'Fusion Plating — Shop Floor',
- 'version': '19.0.9.0.0',
+ 'version': '19.0.10.0.0',
'category': 'Manufacturing/Plating',
'summary': 'Shop-floor tablet stations, QR scanning, bake window enforcer, '
'first-piece inspection gates.',
diff --git a/fusion_plating/fusion_plating_shopfloor/static/src/scss/fusion_plating_shopfloor.scss b/fusion_plating/fusion_plating_shopfloor/static/src/scss/fusion_plating_shopfloor.scss
index 8c4fac2e..2466f13d 100644
--- a/fusion_plating/fusion_plating_shopfloor/static/src/scss/fusion_plating_shopfloor.scss
+++ b/fusion_plating/fusion_plating_shopfloor/static/src/scss/fusion_plating_shopfloor.scss
@@ -34,10 +34,14 @@
padding: $fp-space-6 $fp-space-7;
display: flex;
flex-direction: column;
- gap: $fp-space-6;
+ gap: $fp-space-5;
- @media (max-width: 900px) { padding: $fp-space-4; gap: $fp-space-4; }
- @media (max-width: 600px) { padding: $fp-space-3; gap: $fp-space-4; }
+ // Tablet sweet spot — iPad landscape (1024) and portrait (768).
+ // The goal is to fit Hero + KPIs + Active WO + the first row of
+ // panels in a single 768-tall viewport.
+ @media (max-width: 1180px) { padding: $fp-space-4 $fp-space-5; gap: $fp-space-4; }
+ @media (max-width: 900px) { padding: $fp-space-4; gap: $fp-space-3; }
+ @media (max-width: 600px) { padding: $fp-space-3; gap: $fp-space-3; }
// -------------------------------------------------------------------------
@@ -62,12 +66,18 @@
margin: 0;
color: $fp-ink;
display: flex; align-items: center; gap: $fp-space-3;
+
+ // Smaller hero on tablet — saves ~16px of vertical space without
+ // losing the page identity.
+ @media (max-width: 1180px) { font-size: $fp-text-xl; gap: $fp-space-2; }
}
.o_fp_tablet_subtitle {
margin-top: $fp-space-2;
font-size: $fp-text-sm;
color: $fp-ink-mute;
display: flex; flex-wrap: wrap; gap: $fp-space-3; align-items: center;
+
+ @media (max-width: 1180px) { margin-top: $fp-space-1; }
}
.o_fp_tablet_chip {
display: inline-flex;
@@ -93,7 +103,10 @@
.o_fp_station_picker {
min-width: 240px;
min-height: $fp-touch-min;
- padding: $fp-space-2 $fp-space-4;
+ // Reserve room on the right so the custom chevron has breathing
+ // space between itself and the rounded corner — the native arrow
+ // hugs the edge in Odoo's frame, which looked cramped on iPad.
+ padding: $fp-space-2 $fp-space-7 $fp-space-2 $fp-space-4;
border: 1px solid #{$fp-border};
border-radius: $fp-radius-md;
background-color: $fp-card;
@@ -103,6 +116,20 @@
cursor: pointer;
transition: box-shadow $fp-dur $fp-ease, border-color $fp-dur $fp-ease;
+ // Suppress the browser's native chevron and paint our own. The
+ // SVG is inlined (data URL) so it renders crisply at any DPI and
+ // doesn't trigger an extra HTTP request. Stroke uses currentColor
+ // so it follows light/dark mode automatically.
+ appearance: none;
+ -webkit-appearance: none;
+ -moz-appearance: none;
+ background-image: url("data:image/svg+xml;utf8,");
+ background-repeat: no-repeat;
+ // Inset from the right edge so the chevron sits inside the
+ // padded zone, not flush with the border radius.
+ background-position: right $fp-space-4 center;
+ background-size: 12px 8px;
+
&:focus { @include fp-focus-ring; border-color: $fp-accent; }
@media (max-width: 600px) { min-width: 0; width: 100%; }
}
@@ -205,6 +232,16 @@
grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
gap: $fp-space-4;
+ // iPad landscape (1024) — six 130px tiles + gaps fit on one row.
+ // Keeps the KPI strip a single line so the dashboard can stay above
+ // the fold.
+ @media (max-width: 1180px) {
+ grid-template-columns: repeat(6, minmax(0, 1fr));
+ gap: $fp-space-3;
+ }
+ @media (max-width: 820px) {
+ grid-template-columns: repeat(3, 1fr);
+ }
@media (max-width: 600px) {
grid-template-columns: repeat(2, 1fr);
gap: $fp-space-3;
@@ -220,6 +257,15 @@
display: flex; flex-direction: column; gap: $fp-space-2;
transition: transform $fp-dur $fp-ease, box-shadow $fp-dur $fp-ease;
+ @media (max-width: 1180px) {
+ padding: $fp-space-3 $fp-space-4;
+ gap: $fp-space-1;
+ .o_fp_kpi_value { font-size: $fp-text-xl; }
+ .o_fp_kpi_label { font-size: $fp-text-xs; }
+ // Pull the status dot in so it doesn't crowd small tiles
+ &::after { top: $fp-space-3; right: $fp-space-3; width: 8px; height: 8px; }
+ }
+
@include fp-hover-only {
&:hover {
transform: translateY(-2px);
@@ -286,6 +332,7 @@
box-shadow: $fp-elev-1;
color: $fp-ink;
+ @media (max-width: 1180px) { padding: $fp-space-3 $fp-space-4; }
@media (max-width: 600px) {
flex-direction: column; align-items: stretch;
> .btn { width: 100%; min-height: $fp-touch-min; }
@@ -327,12 +374,17 @@
grid-template-columns: minmax(0, 1.1fr) minmax(0, 1fr);
gap: $fp-space-5;
- @media (max-width: 1100px) { grid-template-columns: 1fr; }
- @media (max-width: 600px) { gap: $fp-space-3; }
+ // Keep the two-column layout down to iPad portrait (768) so the
+ // queue and the bath/bake panels stay side-by-side instead of
+ // stacking. Below that the single-column layout still kicks in.
+ @media (max-width: 1180px) { gap: $fp-space-3; }
+ @media (max-width: 760px) { grid-template-columns: 1fr; }
+ @media (max-width: 600px) { gap: $fp-space-3; }
}
.o_fp_right_col {
- display: flex; flex-direction: column; gap: $fp-space-5;
- @media (max-width: 600px) { gap: $fp-space-3; }
+ display: flex; flex-direction: column; gap: $fp-space-4;
+ @media (max-width: 1180px) { gap: $fp-space-3; }
+ @media (max-width: 600px) { gap: $fp-space-3; }
}
@@ -345,7 +397,8 @@
border-radius: $fp-radius-lg;
box-shadow: $fp-elev-1;
padding: $fp-space-5;
- @media (max-width: 600px) { padding: $fp-space-4; }
+ @media (max-width: 1180px) { padding: $fp-space-4; }
+ @media (max-width: 600px) { padding: $fp-space-4; }
}
.o_fp_panel_head {
display: flex;
@@ -355,6 +408,14 @@
padding-bottom: $fp-space-3;
border-bottom: 1px solid #{$fp-border};
+ @media (max-width: 1180px) {
+ margin-bottom: $fp-space-3;
+ padding-bottom: $fp-space-2;
+ h3 { font-size: $fp-text-base;
+ > .fa { width: 28px; height: 28px; font-size: 0.85rem; }
+ }
+ }
+
h3 {
font-size: $fp-text-lg;
font-weight: $fp-weight-bold;
@@ -402,6 +463,15 @@
opacity: 0.5;
margin-bottom: $fp-space-3;
}
+
+ // On tablet, the "All caught up" state was eating ~140px of
+ // vertical space per panel. Halve it so the dashboard stays
+ // dense even when one or two panels are empty.
+ @media (max-width: 1180px) {
+ padding: $fp-space-4 $fp-space-3;
+ font-size: $fp-text-sm;
+ i.fa { font-size: 1.75rem; margin-bottom: $fp-space-2; }
+ }
}
@@ -422,6 +492,12 @@
border-radius: $fp-radius-md;
background-color: $fp-card;
min-height: 64px;
+
+ @media (max-width: 1180px) {
+ grid-template-columns: 36px 1fr auto;
+ padding: $fp-space-2 $fp-space-3;
+ min-height: 52px;
+ }
transition: background-color $fp-dur $fp-ease,
border-color $fp-dur $fp-ease,
box-shadow $fp-dur $fp-ease,
@@ -463,6 +539,8 @@
font-size: 0.72rem;
letter-spacing: 0.04em;
+ @media (max-width: 1180px) { width: 32px; height: 32px; }
+
&[data-priority="high"] { @include fp-pill(--bs-danger); }
&[data-priority="med"] { @include fp-pill(--bs-warning); }
&[data-priority="low"] { background-color: $fp-card-soft; color: $fp-ink-mute; }
@@ -561,6 +639,12 @@
border-radius: $fp-radius-md;
background-color: $fp-card;
min-height: 64px;
+
+ @media (max-width: 1180px) {
+ padding: $fp-space-2 $fp-space-3;
+ min-height: 48px;
+ gap: $fp-space-2;
+ }
transition: box-shadow $fp-dur $fp-ease, border-color $fp-dur $fp-ease;
@include fp-hover-only { &:hover { box-shadow: $fp-elev-2; } }
diff --git a/fusion_plating/fusion_plating_shopfloor/static/src/xml/shopfloor_tablet.xml b/fusion_plating/fusion_plating_shopfloor/static/src/xml/shopfloor_tablet.xml
index 7ed7286e..b8f8d9b2 100644
--- a/fusion_plating/fusion_plating_shopfloor/static/src/xml/shopfloor_tablet.xml
+++ b/fusion_plating/fusion_plating_shopfloor/static/src/xml/shopfloor_tablet.xml
@@ -36,6 +36,7 @@