diff --git a/Dockerfile b/Dockerfile index 4337782..66b94cd 100644 --- a/Dockerfile +++ b/Dockerfile @@ -107,13 +107,15 @@ RUN set -eux; \ composer dump-autoload --classmap-authoritative --no-dev; \ composer dump-env prod; \ rm -f .env; \ + composer run-script --no-dev post-install-cmd; \ + php bin/console asset-map:compile --no-debug; \ # Strip deployment secrets from the compiled .env.local.php so they cannot be read from the # image layers. The listed keys must be injected as real environment variables at runtime; # Symfony will raise a clear error rather than silently using the public .env.dist defaults. + # Done LAST: cache:clear and asset-map:compile both boot the Symfony kernel and need the env + # vars resolved; stripping before them causes "Environment variable not found" errors. # MAINTENANCE: if a new secret is added to .env.dist, add it here too so it is not # compiled into the image. Use array_diff_key so the strip is explicit and order-independent; # missing keys are safely ignored (they were never compiled in and therefore never a risk). php -r '$strip=array_flip(["APP_SECRET","DATABASE_URL","MYSQL_USER","MYSQL_PASSWORD","MYSQL_ROOT_PASSWORD"]); $e=array_diff_key(include(".env.local.php"),$strip); file_put_contents(".env.local.php"," { + if (!this.hasBarTarget) { + return; + } this.barTarget.style.transition = 'none'; this.barTarget.style.width = '0'; this.barTarget.style.removeProperty('transition'); diff --git a/assets/styles/app.css b/assets/styles/app.css index 55f112f..13844ec 100644 --- a/assets/styles/app.css +++ b/assets/styles/app.css @@ -102,17 +102,37 @@ strong:not(>h2), .strong { a { color: var(--color-secondary); - text-decoration: none; + /* WCAG 1.4.1: links must have a non-colour cue (underline) so they are identifiable + without relying on colour alone. UI-chrome zones (nav, buttons, cards, badges) + suppress it below. */ + text-decoration: underline; + text-underline-offset: 0.18em; } a:hover { + color: var(--color-link-hover); text-decoration: underline; } +/* Cards: the whole card is the interactive element; suppress underline on heading/image links. */ +.card a, .card a:hover { text-decoration: none; - color: var(--color-text); - cursor: pointer; +} + +/* Buttons used as links. */ +.btn, +a.btn, +button a { + text-decoration: none; +} + +/* Tags, badges — clearly interactive chips. */ +a.tag, +.tags a, +.user-badge, +.user-badge:hover { + text-decoration: none; } .card a:hover h2 { @@ -1089,9 +1109,9 @@ svg.icon { padding: 0.12em 0 0.08em; } - #site-header .header__logo-circle { - width: 40px; - height: 40px; + #site-header .header__logo-banner { + width: 100px; + height: 38px; } .hamburger { @@ -1104,37 +1124,26 @@ svg.icon { } } -/* Fixed square + overflow clips to a true circle. Logo img is out-of-flow so - global img { height: auto } cannot shrink the bitmap; object-fit fills the disc. - Slight scale crops typical padding baked into square marketing PNGs. */ -.header__logo-circle { - display: inline-block; - position: relative; - width: 60px; - height: 60px; +/* Horizontal banner logo: portrait painting cropped to a wide strip that shows the + subject's face/upper body. object-position 50% 14% targets the face at the top + of the portrait; adjust the Y value if the crop drifts on a different painting. */ +.header__logo-banner { + display: block; flex-shrink: 0; - border-radius: 50%; - overflow: hidden; - box-shadow: 0 0 0 1px var(--color-border); - vertical-align: middle; -} - -#site-header .header__logo-circle { - width: 48px; + /* Width drives the banner proportions; height clips into the portrait. */ + width: 140px; height: 48px; + object-fit: cover; + object-position: 50% 14%; + border-radius: 5px; + box-shadow: 0 0 0 1px var(--color-border); + /* Prevent global img { height: auto } from overriding the fixed height. */ + max-width: none; } -.header__logo-circle > img { - position: absolute; - inset: 0; - width: 100%; - height: 100%; - max-width: none; - object-fit: cover; - object-position: center; - display: block; - transform: scale(1.18); - transform-origin: center center; +#site-header .header__logo-banner { + width: 120px; + height: 44px; } .header__logo a:hover { @@ -1192,7 +1201,9 @@ footer p { } footer a { - color: var(--color-text-contrast); + /* --color-text-contrast is nearly invisible on the footer background; use the + dedicated footer-link token which has ≥4.5:1 contrast in both schemes. */ + color: var(--color-footer-link); } /* Tags container */ @@ -1335,12 +1346,13 @@ a.tag:focus-visible { } .author-profile__section-type { - font-size: 0.72rem; + font-size: 0.78rem; font-weight: 600; text-transform: uppercase; letter-spacing: 0.04em; - color: var(--color-text); - opacity: 0.75; + /* Use --color-text-mid directly rather than --color-text at opacity: 0.75, which + falls below 3:1 on dark backgrounds; text-mid has ≥7:1 in both schemes. */ + color: var(--color-text-mid); line-height: 1.35; padding-top: 0.15em; } @@ -1386,12 +1398,11 @@ a.tag:focus-visible { } .author-profile__identity-type { - font-size: 0.72rem; + font-size: 0.78rem; font-weight: 600; text-transform: uppercase; letter-spacing: 0.04em; - color: var(--color-text); - opacity: 0.75; + color: var(--color-text-mid); } .author-profile__meta-value, @@ -1459,12 +1470,11 @@ a.tag:focus-visible { } .author-profile__payment-type { - font-size: 0.72rem; + font-size: 0.78rem; font-weight: 600; text-transform: uppercase; letter-spacing: 0.04em; - color: var(--color-text); - opacity: 0.75; + color: var(--color-text-mid); } .author-profile__jumble { @@ -1722,9 +1732,9 @@ a:focus-visible { font-size: clamp(0.88rem, 4.4vw, 1.12rem); } - #site-header .header__logo-circle { - width: 36px; - height: 36px; + #site-header .header__logo-banner { + width: 88px; + height: 34px; } } diff --git a/assets/styles/article.css b/assets/styles/article.css index 3b9637a..7da3768 100644 --- a/assets/styles/article.css +++ b/assets/styles/article.css @@ -139,9 +139,9 @@ margin: 2rem 0; padding-top: 0.5rem; border-top: 1px solid var(--color-border); - font-size: 0.88rem; + font-size: 1rem; font-weight: 400; - color: color-mix(in srgb, var(--color-text-mid) 58%, var(--color-bg) 42%); + color: var(--color-text-mid); font-family: var(--font-family), sans-serif; } @@ -204,6 +204,7 @@ margin-left: -30px; line-height: 1.2; color: var(--color-secondary); + text-decoration: none; } .heading-permalink:hover { @@ -297,7 +298,7 @@ border-left: 2px solid color-mix(in srgb, var(--color-border) 50%, transparent); background: color-mix(in srgb, var(--color-bg-light) 55%, transparent); border-radius: 0 3px 3px 0; - font-size: 0.82em; + font-size: 0.9em; line-height: 1.45; color: var(--color-text-mid); } diff --git a/assets/styles/form.css b/assets/styles/form.css index 432c489..a20f23f 100644 --- a/assets/styles/form.css +++ b/assets/styles/form.css @@ -29,7 +29,7 @@ input:focus, textarea:focus { } .help-text { - font-size: 0.8rem; + font-size: 0.875rem; color: var(--color-text); font-weight: lighter; } diff --git a/assets/styles/layout.css b/assets/styles/layout.css index b1b165b..9b5a85f 100644 --- a/assets/styles/layout.css +++ b/assets/styles/layout.css @@ -696,7 +696,7 @@ aside { border-radius: 0; background: transparent; line-height: 1.45; - font-size: 0.78rem; + font-size: 0.875rem; transition: color 0.18s ease, background 0.18s ease; } @@ -744,7 +744,7 @@ aside { /* Match article `bodyHtml` semantics; keep aside scale (`.user-highlight__body` is larger in-article). */ .home-aside-highlights__quote--html.user-highlight__body { margin: 0 0 0.3rem; - font-size: 0.78rem; + font-size: 0.875rem; line-height: 1.45; color: inherit; } @@ -758,7 +758,7 @@ aside { .home-aside-highlights__meta { display: block; - font-size: 0.78rem; + font-size: 0.875rem; font-style: normal; font-weight: 500; font-family: var(--font-family), system-ui, sans-serif; @@ -1067,9 +1067,8 @@ footer { .site-footer__syndication-hint { margin: 0 0 0.75rem; - font-size: 0.9rem; + font-size: 1rem; color: var(--color-text); - opacity: 0.9; max-width: 40rem; } diff --git a/assets/styles/magazine-editor.css b/assets/styles/magazine-editor.css index b52f3e1..71386f8 100644 --- a/assets/styles/magazine-editor.css +++ b/assets/styles/magazine-editor.css @@ -238,23 +238,21 @@ min-width: 0; } +/* Drag handle is a (not a