Skip to main content
ENKO

Layout

Layout controls how Senco screens are structured and how content reflows across screen sizes.

Senco is mobile-first in the literal sense: the phone layout is the design, and the desktop layout is the phone layout given more room. That ordering is what keeps the two from drifting into different products, and it is why the transfer flow looks the same shape on a 1440px monitor as it does on a 360px handset.

Grid system

Column-based responsive grid that adapts across breakpoints. Content reflows — it never shrinks.

BreakpointWidthColumnsGutterMargin
Mobile< 600px416px16px
Tablet600–1023px816px24px
Desktop1024–1439px1224px32px
Wide≥ 1440px1224pxauto (max 1400px)

Breakpoint tokens: --ds-bp-mobile (600px), --ds-bp-tablet (1024px), --ds-bp-desktop (1440px).

Reflow, never shrink

Content moving to a smaller screen changes how many columns it spans. It does not scale down. A 16px label stays 16px at every breakpoint; what changes is that a three-column card row becomes a single stacked column.

Shrinking is how a design system ends up with 13px text on the exact devices whose users need it largest.

Column spans by breakpoint

ContentMobile (4)Tablet (8)Desktop (12)
Full-width section4812
Card in a row of three4 (stacked)4 (two per row)4 (three per row)
Transfer flow column46 centered4 centered
Dashboard main / side4 / 4 stacked8 / 8 stacked8 / 4
Settings nav / panel4 (tabs on top)8 (tabs on top)3 / 9

The transfer flow narrows as the screen widens — from 4 of 4 columns to 4 of 12. This is deliberate and is the clearest expression of the mobile-first rule: more space does not mean a wider form, it means more margin around the same form.

Breakpoints are for layout, not for components

A component never queries the viewport. It fills the container it is given, and the layout decides how wide that container is. A card that reads @media (max-width: 600px) breaks the moment it is placed in a sidebar on desktop.

Where a component genuinely needs to respond to its own width — a transaction row that drops its secondary line when narrow — it uses a container query, not a media query.

Responsive grid — columns, gutters, margins
1024–1439px
32px
24px
Breakpoint
1024–1439px
Columns
12
Gutter
24px
space-5
Margin
32px
space-6
Container
Fluid
Column spanning
span 12 — header
span 3
span 9 — hero
span 3
span 3
span 3
span 12 — footer
Sidebar (3) + content area (9) with 3-column card grid.

Containers

TypeBehaviorUsage
FluidFills available widthFull-width sections
ConstrainedMax-width with centered contentDefault content pages
Full-bleedEdge-to-edge, ignores page paddingHero banners, backgrounds

Constrained widths come from the sizing tokens — --ds-container-xs through --ds-container-max. See Sizing.

Choosing a container

ScreenContainerWhy
Transfer flowsm (480px)Single-column sequence; wider invites out-of-order scanning
Settingslg (960px)Two-column nav + panel on desktop
Dashboardlg (960px)Main column plus a side rail
Documentation / contentmd (640px)Keeps line length inside 45–75 characters
Marketing heroFull-bleedBackground extends past the content column

Full-bleed with constrained content

A full-bleed section is edge-to-edge in background only. Its text still sits in a constrained container, because a headline running 1400px wide is unreadable regardless of how good the background looks.

Do / Don't
Do

Content centered in a constrained container with margins. Comfortable reading.

Don't

Content stretches edge-to-edge. Line lengths become unreadable on wide screens.

Layout primitives

PrimitivePurpose
ContainerConstrain content width and apply horizontal padding
GridArrange content in responsive columns
StackVertical sequence with a single consistent gap
RowHorizontal sequence with a single consistent gap, wrapping by default

Stack and Row exist so that spacing lives in one place. A screen built from Stacks has exactly one gap value per group and no margins on children — which is the rule from Spacing enforced by structure rather than by review.

Header and Footer are template-level regions — see Templates > Basic page.

Safe areas

Mobile layouts respect env(safe-area-inset-*). The bottom tab bar and the persistent action bar both sit above the home indicator; without the inset the primary transfer action lands underneath the gesture bar, where roughly a third of taps are swallowed by the OS.

Responsive principles

  • Mobile-first approach — base styles are mobile, enhance with breakpoints
  • Navigation adapts: bottom tabs on mobile, sidebar on desktop
  • Touch targets meet the 48px minimum on mobile
  • Column spanning changes per breakpoint (e.g., 3-col cards on desktop stack to single column on mobile)
  • Content reflows at 320px width and 200% zoom without horizontal scrolling (WCAG 1.4.10)
  • Layout is defined in rem and fractional units, so OS text scaling reflows rather than clips

Do and don't

DoDon't
Let the transfer flow stay 480px on a wide screenStretch a single-column form to fill 1200px
Reflow a three-card row into a stackScale three cards down to fit side by side on mobile
Use a container query for component-level responsePut a viewport media query inside a component
Apply safe-area insets to fixed bottom chromePin an action bar to bottom: 0 and lose it under the home indicator
Keep gaps on the parent via gapAdd margins to grid children to fake a gutter

Design and accessibility

  • Use semantic landmarks (header, main, footer, nav)
  • Grid does not break reading order for screen readers — visual order and DOM order must match
  • order and row-reverse are prohibited where they would separate the two
  • Container does not trap keyboard focus
  • One <main> per page, and the skip link targets it
  • Landmarks are labelled when repeated (two <nav> elements need distinguishing aria-labels)

Known gaps

ItemStatus
Stack / Row primitivesDocumented here; not implemented as shipped components
Container queriesDocumented as the preferred mechanism; not yet used in any component
Grid column tokensColumn counts and gutters are documented but not defined as --ds- variables
Safe-area handlingApplied on prototype screens; not systematized as a layout primitive