mobile h2 + sky wheel landscape fit: per-letter flex spread (justify-content: space-between via base.html JS letter-splitter) replaces text-justify: inter-character — iOS Safari + Firefox silently fall back to inter-word for Latin text, leaving letters clustered at the slot start; flex layout works everywhere; viewport-fluid font clamp(1.3rem, 5vw, 2rem) portrait + clamp(1.2rem, 4.4vh, 2.75rem) landscape so glyphs scale w. viewport instead of a fixed-rem ceiling that overflowed the 45/55 slot at the rem-clamp floor; portrait <500px gets padding-inline 0.4em→0.6em on the word-spans so H-B don't run together at the cramped font-size; .sky-page post-save scroll-snap sections pinned to height: 100% (was: min-height: 100%) + .sky-svg max-height: 100% so the wheel fits exactly one aperture on landscape mobile (was: 480px max blew past ~350px aperture, leaving an intermediate scroll position)
All checks were successful
ci/woodpecker/push/pyswiss Pipeline was successful
ci/woodpecker/push/main Pipeline was successful

Code architected by Disco DeDisco <discodedisco@outlook.com>
Git commit message Co-Authored-By:
Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Disco DeDisco
2026-05-09 14:01:16 -04:00
parent 22d0507c3f
commit df99cad984
3 changed files with 75 additions and 15 deletions

View File

@@ -210,10 +210,20 @@ body {
var(--title-shadow-offset) var(--title-shadow-offset) 0 rgba(0, 0, 0, 0.8) var(--title-shadow-offset) var(--title-shadow-offset) 0 rgba(0, 0, 0, 0.8)
; ;
// Each word-span hosts per-letter <span>s injected by the
// h2-letter-split script in base.html — display: flex +
// justify-content: space-between distributes those letters
// across the slot's width (or height in landscape's
// writing-mode: vertical-rl). text-justify: inter-character
// would do the same in pure CSS, but iOS Safari + Firefox
// silently fall back to inter-word for Latin scripts, which
// can't split a single word — letters end up clustered at
// the slot's start with empty space trailing. The flex
// approach works everywhere.
> span { > span {
text-align: justify; display: flex;
text-align-last: justify; justify-content: space-between;
text-justify: inter-character; align-items: center;
box-sizing: border-box; box-sizing: border-box;
} }
// Padding-inline (logical) creates the natural visual gap // Padding-inline (logical) creates the natural visual gap
@@ -365,8 +375,14 @@ body {
height: 80vh; // explicit height so the flex 45/55 % basis resolves height: 80vh; // explicit height so the flex 45/55 % basis resolves
transform: translateY(-50%) rotate(180deg); transform: translateY(-50%) rotate(180deg);
writing-mode: vertical-rl; // inline axis becomes top-to-bottom; flex stacks on it writing-mode: vertical-rl; // inline axis becomes top-to-bottom; flex stacks on it
font-size: 3rem; // rem-fluid → no min-height jumps // Per-letter flex spread (justify-content: space-between on each word
letter-spacing: 0.4em; // span) fills the slot regardless of font-size, so we only need to
// cap font-size by vh so each letter glyph stays smaller than slot /
// letter-count. Worst case: HOWDY STRANGER (8ch second word) in 55%
// of 80vh on a 375-tall iPhone SE landscape → 165px slot ÷ 8 ≈ 20px
// max glyph height; clamp's 4.4vh + 1.2rem floor gives 16.516.8px
// at that viewport, well under 20.
font-size: clamp(1.2rem, 4.4vh, 2.75rem);
margin: 0; margin: 0;
z-index: 85; z-index: 85;
pointer-events: none; pointer-events: none;
@@ -476,16 +492,20 @@ body {
} }
} }
// Per-letter flex spread fills each 45/55 slot regardless of font-size,
// so we just need to cap the glyph size by viewport width to keep the
// worst-case title (HOWDY STRANGER, 8ch second word) from clipping at
// tiny mobile widths. clamp picks max(1.3rem, 5vw) capped at 2rem —
// at 320w → 18.2px, 390w → 19.5px, 430w → 21.5px.
// padding-inline boundary bumped from 0.4em → 0.6em (each side) so the
// last letter of word 1 (H) and first letter of word 2 (B) don't run
// together at the cramped portrait font-size.
.row .col-lg-6 h2 { .row .col-lg-6 h2 {
text-align: center;
text-align-last: center;
letter-spacing: 0.33em;
margin: 0; margin: 0;
font-size: 2rem; font-size: clamp(1.3rem, 5vw, 2rem);
&#id_dash_wallet { > span:first-child { padding-inline-end: 0.6em; }
letter-spacing: 0.25em; > span:last-child { padding-inline-start: 0.6em; }
}
} }
} }
} }

View File

@@ -1089,18 +1089,32 @@ body.sky-saved {
.sky-page .sky-form-col { .sky-page .sky-form-col {
scroll-snap-align: start; scroll-snap-align: start;
scroll-snap-stop: always; scroll-snap-stop: always;
min-height: 100%; // height (not min-height) pins each section to EXACTLY one aperture so
// the snap-stops land at integer multiples of the viewport. min-height
// alone let .sky-svg's 480px max-height push the wheel section past one
// viewport on landscape mobile (~350px aperture), which created an
// intermediate scroll position between the wheel-end and the form-start.
height: 100%;
flex: 0 0 auto; flex: 0 0 auto;
} }
// Release the wheel-col aspect-ratio cap so the section fills the aperture; // Release the wheel-col aspect-ratio cap so the section fills the aperture;
// .sky-svg inside still renders square (its own aspect-ratio:1/1) and stays // .sky-svg inside still renders square (its own aspect-ratio:1/1) and stays
// centered via the col's align-items:center. // centered via the col's align-items:center. max-height: 100% caps the SVG
// to the aperture height — without it the .sky-svg's 480px max-* would let
// the wheel render taller than the section, overflowing into the form-col
// on cramped landscape phones.
.sky-page .sky-wheel-col { .sky-page .sky-wheel-col {
aspect-ratio: auto; aspect-ratio: auto;
max-width: none; max-width: none;
max-height: none; max-height: 100%;
width: 100%; width: 100%;
overflow: hidden;
.sky-svg {
max-width: 100%;
max-height: 100%;
}
} }
// form-col loses its grow/min-height fill so the snap basis (min-height:100% // form-col loses its grow/min-height fill so the snap basis (min-height:100%

View File

@@ -74,6 +74,32 @@
{% block scripts %} {% block scripts %}
{% endblock scripts %} {% endblock scripts %}
<script> <script>
// h2 letter splitter — wrap each character of every .row .col-lg-6 h2
// word-span in its own <span> so .scss can use justify-content:
// space-between to fill the 45/55 slot. text-justify: inter-character
// would do this in pure CSS but iOS Safari + Firefox silently fall
// back to inter-word for Latin text, leaving letters clustered at the
// slot's start.
(function () {
var spans = document.querySelectorAll('.row .col-lg-6 h2 > span');
for (var i = 0; i < spans.length; i++) {
var span = spans[i];
if (span.dataset.lettersSplit === '1') continue;
var text = (span.textContent || '').trim();
if (!text) continue;
span.dataset.lettersSplit = '1';
span.setAttribute('aria-label', text);
span.textContent = '';
for (var j = 0; j < text.length; j++) {
var letter = document.createElement('span');
letter.setAttribute('aria-hidden', 'true');
letter.textContent = text[j];
span.appendChild(letter);
}
}
}());
</script>
<script>
(function () { (function () {
var portal = null; var portal = null;
var _cb = null; var _cb = null;