The starter is mobile friendly out of the box, so the layouts, navigation, and menus all work on a small screen without a separate mobile build.
Off-canvas menus are built on a SheetMenu composite that wraps the shadcn sheet primitive. It takes a side, left or right, a width, and a header height, and gives you a slide-out panel with a logo header, a scrollable body, an optional footer slot, and a close button already wired up. App-level menus like the account and notifications panels are thin features built on top of it rather than each rebuilding the same shell.
Three conveniences are baked in. The panel closes itself when you click a link inside it, so anchor navigation does not leave a menu hanging open, and the accessible name is handled through a visually hidden title so screen readers announce the menu without you thinking about it per instance. It also closes whenever a dialog opens, so a dialog triggered from inside the menu is not left sitting on top of it.
Tailwind's breakpoints only go one way, sm: and up, so hiding something on mobile means hidden sm:flex. That works, but you have to restate the display type on the way back, and if the element already had one from a component or a utility you now own it by hand.
unhidden is the complement to hidden, available at every breakpoint. sm:unhidden hides an element below sm and leaves its display alone above, so nothing has to be restored. It's a handful of lines in shared/assets/utilities.css and it reads the same way round as the rest of Tailwind.
Component Architecture for why SheetMenu is a composite over the sheet primitive rather than an edit to the primitive itself. Layouts for how the menus slot into the wider layout.