Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 49 additions & 3 deletions landing/hero-p0.css
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/* ARSAS P0 hero refinement.
Desktop-only composition fixes based on production visual review.
Desktop composition + localized-copy safety based on production visual review.
Keeps content, SEO, release sync and mobile behavior unchanged. */

@media (min-width: 981px) {
Expand All @@ -24,16 +24,21 @@
}

.hero h1 {
max-width: 34rem;
max-width: min(36.5rem, 100%);
margin-top: 1.22rem;
font-size: clamp(3.65rem, 4.35vw, 4.08rem);
line-height: 1.025;
letter-spacing: -.046em;
}

/* Never make translated headline length part of the layout contract.
English still remains on one line where it naturally fits; longer locales
may wrap instead of escaping the text column and being clipped by .hero. */
.hero h1 .gradient-text {
display: block;
white-space: nowrap;
max-inline-size: 100%;
white-space: normal;
text-wrap: balance;
}

.hero-copy {
Expand Down Expand Up @@ -85,6 +90,32 @@
right: -.7rem;
bottom: 11%;
}

/* Indonesian copy is materially longer than English. Give the message and
product equal authority instead of shrinking or clipping the translation. */
.hero:lang(id) .hero-grid {
grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
gap: clamp(1.85rem, 2.8vw, 2.6rem);
}

.hero:lang(id) h1 {
max-width: min(36.5rem, 100%);
font-size: clamp(3.45rem, 4.05vw, 3.86rem);
}

.hero:lang(id) .hero-copy {
max-width: 36rem;
}

.hero:lang(id) .eyebrow {
max-width: 100%;
white-space: normal;
line-height: 1.35;
}

.hero:lang(id) .hero-visual {
width: 105%;
}
}

@media (min-width: 981px) and (max-width: 1180px) {
Expand All @@ -109,4 +140,19 @@
.hero-visual {
width: 104%;
}

/* At compact desktop widths localized controls may wrap deliberately.
This is preferable to horizontal overflow or hidden actions. */
.hero:lang(id) h1 {
font-size: clamp(3.25rem, 4.75vw, 3.55rem);
}

.hero:lang(id) .hero-actions,
.hero:lang(id) .hero-proof {
flex-wrap: wrap;
}

.hero:lang(id) .hero-visual {
width: 102%;
}
}
43 changes: 43 additions & 0 deletions tests/ARSAS.Tests/WebsiteHeroLocalizationRegressionTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
namespace ARSAS.Tests;

public sealed class WebsiteHeroLocalizationRegressionTests
{
[Fact]
public void HeroGradientHeadline_AllowsLocalizedCopyToWrapInsteadOfClipping()
{
var css = Read("landing/hero-p0.css").Replace("\r\n", "\n", StringComparison.Ordinal);

Assert.Contains(".hero h1 .gradient-text", css, StringComparison.Ordinal);
Assert.Contains("white-space: normal;", css, StringComparison.Ordinal);
Assert.DoesNotContain(
".hero h1 .gradient-text {\n display: block;\n white-space: nowrap;",
css,
Comment on lines +11 to +14

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Scope the wrapping assertion to the gradient rule

If .hero h1 .gradient-text is changed back to white-space: nowrap, this regression test still passes: the positive assertion finds white-space: normal in the Indonesian eyebrow rule, while the negative assertion cannot match the current gradient block because max-inline-size appears between display and white-space. Extract or otherwise inspect the gradient rule itself so the advertised clipping regression is actually detected.

Useful? React with 👍 / 👎.

StringComparison.Ordinal);
}

[Fact]
public void IndonesianHero_HasDedicatedDesktopSafetyRules()
{
var css = Read("landing/hero-p0.css");

Assert.Contains(".hero:lang(id) .hero-grid", css, StringComparison.Ordinal);
Assert.Contains(".hero:lang(id) h1", css, StringComparison.Ordinal);
Assert.Contains(".hero:lang(id) .eyebrow", css, StringComparison.Ordinal);
Assert.Contains(".hero:lang(id) .hero-actions", css, StringComparison.Ordinal);
Assert.Contains("flex-wrap: wrap;", css, StringComparison.Ordinal);
}

private static string Read(string relativePath)
{
DirectoryInfo? directory = new(AppContext.BaseDirectory);
while (directory != null)
{
var candidate = Path.Combine(directory.FullName, relativePath);
if (File.Exists(candidate))
return File.ReadAllText(candidate);
directory = directory.Parent;
}

throw new FileNotFoundException(relativePath);
}
}
Loading