--- name: frontend-mobile-rules description: Frontend for mobile first styling, MUI, and iOS safe-area guidance --- ## Frontend # iOS Safe Areas & Viewport - Always set `viewport-fit=cover` in the viewport meta tag in `index.html`. Without it, `env(safe-area-inset-*)` always returns `0px` on iOS. - Use `100dvh` for full-height layouts with `@supports` progressive enhancement in MUI `sx`: ``` height: '100vh', '@supports (height: 100dvh)': { height: '100dvh' } ``` Never use `100vh` alone on iOS — it doesn't account for the Chrome toolbar. Never use the JS spread pattern `{ height: '100vh', ...{ height: '100dvh' } }` — JS spread overwrites the fallback, breaking browsers without `dvh` support. - Top safe area: add `pt: 'env(safe-area-inset-top, 0px)'` to MUI `Toolbar` components (notch / Dynamic Island). - Bottom safe area: add `pb: 'calc(Npx + env(safe-area-inset-bottom, 0px))'` to bottom-fixed elements (input bars, content areas). Use `theme.spacing()` or the original padding value for `Npx`. - `flexShrink: 0` on bottom input bars prevents them from being compressed in flex column layouts when content overflows. # Component Styling Destinations This project uses MUI sx props, MUI theme overrides (theme.js), AND Tailwind CSS v3 (tailwind.css @layer components + tailwind.config.js theme.extend). All three are valid destinations for component styles. - **MUI `sx` props**: for dynamic or computed styles (values that depend on props, state, or runtime conditions). Example: `sx={{ color: note.color.text }}`. - **MUI theme.js component overrides**: for MUI component default styling that applies globally (e.g. `MuiSelect`, `MuiOutlinedInput`, `MuiButton`). - **Tailwind CSS `@layer components`**: for static, reusable component styles identified by class or id. Use `@apply` with Tailwind utilities + raw CSS for custom properties (`var(--glass-bg)`, etc.). - **Tailwind config `theme.extend`**: for design tokens (colors, fonts, spacing) consumed by both `@apply` in CSS and `sx` in components via `theme('colors.accent')`. # Cascade order (critical) MUI emotion CSS loads BEFORE Tailwind CSS (static file). This means Tailwind `@layer components` rules WIN over MUI `sx` props at equal specificity. Rules: - When moving a style from `sx` to CSS, REMOVE it from `sx` — do NOT leave both active on the same element, or the CSS silently overrides the `sx`. - Never put `display: none`, `visibility: hidden`, or hardcoded colors in CSS for elements that also use `sx` for those properties — the CSS will shadow the `sx`. - Dynamic values (note colors, selection state) must stay in `sx` — CSS cannot receive runtime props. - Do NOT add `