/* Touch screens. A phone's layout uses the width variants (max-md:, md:) at the call site; how big a thing is to a finger uses the pointer: the sizes here sit under @media (pointer: coarse), so a mouse matches none of them and desktop keeps daisyUI's sizes. The rules are plain CSS in Tailwind's utilities layer: like neo.css's @utility overrides they beat daisyUI's rules, which sit in sublayers of it, and they set daisyUI's own size variables where it has one. A target gets a 44px hit area (Apple's guideline, WCAG 2.5.5), which tests/e2e/Mobile measures. Buttons, tabs and fields are 44px tall; the extra small buttons and the badges that act stay 36px to the eye and reach 44px through a transparent ::after, so the rows that hold them leave 8px between them on touch (pointer-coarse:gap-2), or two hit areas would overlap. */ /* A small text link or button (a name, "edited") keeps its size to the eye and gets a 44px hit area, a transparent box centred on it, on touch only. Not for one that truncates its text: its overflow clips the box, so such a link takes padding instead (pointer-coarse:py-3.5). */ @utility touch-target { @media (pointer: coarse) { position: relative; &::after { content: ""; position: absolute; left: 50%; top: 50%; width: max(100%, 2.75rem); height: max(100%, 2.75rem); translate: -50% -50%; } } } /* A short window: a phone held sideways. The globe's banner would leave the feed no room there. */ @custom-variant short (@media (max-height: 30rem)); @layer utilities { /* At every width: a checkbox's, radio's or toggle's label wraps (daisyUI's .label never does, and a long one ran past a phone's edge), and the control keeps its size beside it. */ .label:has(> input[type=checkbox], > input[type=radio], > .toggle) { white-space: normal; text-align: start; & > input { flex-shrink: 0; } } @media (pointer: coarse) { /* Field text at 16px: iOS zooms into a focused field whose text is smaller, now that zooming is allowed. */ :where(.input, .select, .textarea) { --font-size-min: 1rem; } .btn:not(.btn-xs, .btn-lg, .btn-xl) { --size: 2.75rem; min-width: 2.75rem; } .btn-sm { --fontsize: .875rem; } /* (the ::after is placed against the padding box, 34px inside a 1px border: 5px around it makes 44) */ .btn-xs, :is(button, a).badge { --size: 2.25rem; min-width: 2.25rem; position: relative; &::after { content: ""; position: absolute; inset: -5px; } } .btn-xs { --fontsize: .875rem; } :is(button, a).badge { padding-inline: .75rem; } .tabs { --tab-height: 2.75rem; } .tab { min-width: 2.75rem; } .input:not(.input-lg, .input-xl), .select:not(.select-lg, .select-xl), .file-input:not(.file-input-lg, .file-input-xl) { --size: 2.75rem; } .checkbox, .radio { --size: 1.5rem; } .toggle { --size: 1.75rem; } .range { --range-thumb-size: 1.75rem; } .collapse-title, .label:has(> input[type=checkbox], > input[type=radio], > .toggle) { min-height: 2.75rem; } } } /* A sideways strip fades at the edge where more of it waits: the right edge at first, both while scrolled, the left at the end (a scroll-driven animation where the browser has one; without, the right edge only). */ @property --fade-start { syntax: ""; inherits: false; initial-value: 0px; } @property --fade-end { syntax: ""; inherits: false; initial-value: 1.5rem; } @keyframes edge-fade-x { from { --fade-start: 0px; --fade-end: 1.5rem; } 8% { --fade-start: 1.5rem; } 92% { --fade-end: 1.5rem; } to { --fade-start: 1.5rem; --fade-end: 0px; } } @utility edge-fade-x { mask-image: linear-gradient(to right, transparent, #000 var(--fade-start), #000 calc(100% - var(--fade-end)), transparent); @supports (animation-timeline: scroll()) { animation: edge-fade-x linear both; animation-timeline: scroll(self inline); } }