/* Hadid — hadid.fitness
   One stylesheet for all pages. No build step, no framework, no JS
   dependency: these pages exist to be reachable by a store reviewer and
   readable by a user, and every dependency is another way that fails.

   Palette lifted from src/theme/tokens.ts so site and app read as one
   product. Dark is primary; light mirrors the app's light theme. */

/* Self-hosted, copied by scripts/site/fonts.mjs. See that file for why this
   is not the Google Fonts CDN. */
@font-face {
  font-family: Archivo;
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url(/fonts/archivo-latin-700-normal.woff2) format('woff2');
}
@font-face {
  font-family: Archivo;
  font-style: normal;
  font-weight: 800;
  font-display: swap;
  src: url(/fonts/archivo-latin-800-normal.woff2) format('woff2');
}
@font-face {
  font-family: "IBM Plex Sans";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url(/fonts/ibm-plex-sans-latin-400-normal.woff2) format('woff2');
}
@font-face {
  font-family: "IBM Plex Sans";
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url(/fonts/ibm-plex-sans-latin-600-normal.woff2) format('woff2');
}
@font-face {
  font-family: "IBM Plex Mono";
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url(/fonts/ibm-plex-mono-latin-500-normal.woff2) format('woff2');
}
/* The Arabic half of "IBM Plex Mono". Plex Mono is Latin-only, and sixteen
   rules in this file set a `"IBM Plex Mono",monospace` stack -- the eyebrows,
   the kickers, the store buttons' small line, the /app captions and section
   headings, and most of the phone mock. On /ar every one of those resolved
   its Arabic through the second entry, the browser's generic `monospace`,
   which is exactly the silent system fallback self-hosting the fonts exists
   to remove. Measured before fixing, not assumed: "باختصار" set 48px in the
   eyebrow's own stack and 48px in bare `monospace`, against 34px in Plex
   Sans Arabic.
   Composing the family by unicode-range fixes all sixteen at once and keeps
   working for a seventeenth, which a list of selector overrides would not.
   Latin codepoints are untouched: this face declares only the Arabic ranges,
   so Latin still comes from the real Plex Mono above it. The 500 file is
   already shipped -- Task 1 self-hosted ar at 400/500/600 and nothing had
   used 500 until now, which is the weight a mono-styled label wants.
   Hebrew's twin is below. */
@font-face {
  font-family: "IBM Plex Mono";
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url(/fonts/ibm-plex-sans-arabic-arabic-500-normal.woff2) format('woff2');
  unicode-range: U+0600-06FF, U+0750-077F, U+08A0-08FF, U+FB50-FDFF, U+FE70-FEFF;
}
/* The Hebrew half of "IBM Plex Mono", the twin of the block above and for
   the identical reason: Plex Mono has no Hebrew glyphs either, so on /he
   the same sixteen rules resolved their Hebrew through the generic
   `monospace`. Measured on /he before fixing, at 48px, on
   "בקצרה" (home.short.eyebrow): 111.78px in the eyebrow's own
   `"IBM Plex Mono", monospace` stack and 111.78px in bare `monospace` --
   identical to the pixel, which is what a fallback looks like -- against
   136.14px in Plex Sans Hebrew.

   The file is the Hebrew 400, because that is the weight every page
   already fetches for `body` -- Task 1 self-hosted Hebrew at 400 and 600
   only, and 600 is not fetched by the pages that have no Hebrew heading.
   So this face adds no request, exactly as the Arabic one does not.

   The DESCRIPTOR says 500 anyway, and that is deliberate: `font-weight` on
   an @font-face declares which weight slot a file fills, not what is inside
   it, and the slot has to be 500 -- the SAME weight the unranged Latin Plex
   Mono face above declares -- or the composed face is never reached.

   Both halves of that were measured on /he, changing one thing at a time,
   because it is the sort of claim that is easy to get wrong:

     - declared at 400, order untouched: "בקצרה" set 111.78px in the
       eyebrow's stack, exactly bare `monospace`, against 136.14px in Plex
       Sans Hebrew. The fallback is back.
     - declared at 500 but moved ABOVE the unranged Latin face: 136.14px.
       Still correct. Declaration order does NOT matter here.

   So the rule to preserve is weight parity with the Latin face, not
   position, and `serves Arabic and Hebrew inside the mono stack` in
   src/__tests__/website.test.js asserts exactly that. What is going on
   underneath -- the Latin face declares no unicode-range, so it claims
   Hebrew codepoints it has no glyphs for, and something about how the two
   are ranked decides which is consulted -- is NOT pinned down here, and a
   guess dressed up as an explanation would be worse than this sentence:
   the next person should re-measure rather than reason from a story.

   The cost is that Hebrew sets Regular where Latin sets Medium; there is
   no Hebrew 500 to self-host without adding a request. */
@font-face {
  font-family: "IBM Plex Mono";
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url(/fonts/ibm-plex-sans-hebrew-hebrew-400-normal.woff2) format('woff2');
  unicode-range: U+0590-05FF, U+FB1D-FB4F;
}
@font-face {
  font-family: "IBM Plex Sans Arabic";
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url(/fonts/ibm-plex-sans-arabic-arabic-500-normal.woff2) format('woff2');
  unicode-range: U+0600-06FF, U+0750-077F, U+08A0-08FF, U+FB50-FDFF, U+FE70-FEFF;
}
@font-face {
  font-family: "IBM Plex Sans Arabic";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url(/fonts/ibm-plex-sans-arabic-arabic-400-normal.woff2) format('woff2');
  unicode-range: U+0600-06FF, U+0750-077F, U+08A0-08FF, U+FB50-FDFF, U+FE70-FEFF;
}
@font-face {
  font-family: "IBM Plex Sans Arabic";
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url(/fonts/ibm-plex-sans-arabic-arabic-600-normal.woff2) format('woff2');
  unicode-range: U+0600-06FF, U+0750-077F, U+08A0-08FF, U+FB50-FDFF, U+FE70-FEFF;
}
@font-face {
  font-family: "IBM Plex Sans Hebrew";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url(/fonts/ibm-plex-sans-hebrew-hebrew-400-normal.woff2) format('woff2');
  unicode-range: U+0590-05FF, U+FB1D-FB4F;
}
@font-face {
  font-family: "IBM Plex Sans Hebrew";
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url(/fonts/ibm-plex-sans-hebrew-hebrew-600-normal.woff2) format('woff2');
  unicode-range: U+0590-05FF, U+FB1D-FB4F;
}
/* An alias of a file every page already fetches, for one word. The brand
   حديد appears twice OUTSIDE the wordmark -- in the footer's
   `<span class="ar">` on all nine pages, and inside help.about.p4's
   `<strong>` on the three /help pages -- and both sit in a stack (Latin, or
   Hebrew on /he) with no Arabic glyphs. Measured on /he/help: 20.41px in
   the footer and 23.69px in the <strong>, each equal to the generic
   `sans-serif` to the hundredth of a pixel, against 28.78px and 32.72px in
   Plex Sans Arabic.

   Naming the real "IBM Plex Sans Arabic" family would fix it and cost a
   request: the <strong> is weight 600, which matches the Arabic 600 face,
   a file /help and /he/help otherwise never fetch. This alias instead
   declares ONE face across the whole 400-700 range, from the Arabic 500
   file `.wordmark .ar` already loads on every page, so both weights land
   on something the browser has. Verified on the network tab: /help fetches
   seven woff2 and /he/help six, the same sets as before, arabic-500 among
   them exactly once.

   It has its OWN family name on purpose. Adding an Arabic-ranged face to
   "IBM Plex Sans Hebrew" instead was tried first and broke Hebrew: the
   ranged face and the Hebrew face compete at the same weight, and when the
   one that wins has no glyph the browser leaves for the next FAMILY rather
   than trying the other face. "להיסגר" went to 47.59px, exactly the system
   sans-serif, from 41.06px. A family of its own cannot collide with
   anything. */
@font-face {
  font-family: "Hadid Arabic";
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url(/fonts/ibm-plex-sans-arabic-arabic-500-normal.woff2) format('woff2');
  unicode-range: U+0600-06FF, U+0750-077F, U+08A0-08FF, U+FB50-FDFF, U+FE70-FEFF;
}

:root {
  --bg:#14161A; --surf:#1C1F25; --surf2:#23272E; --sunken:#171B21;
  --line:#2E333B; --line2:#2E353F;
  --tx:#F0F2F5; --tx2:#99A1AD; --tx3:#8A929E;
  --amber:#FFB020; --amber-tx:#FFB020; --focus:var(--amber); --amber-soft:rgba(255,176,32,.08);
  --green:#2BB673; --shadow:rgba(0,0,0,.55);
}
@media (prefers-color-scheme: light) {
  :root:not([data-theme="dark"]) {
    --bg:#F2F3F5; --surf:#FFFFFF; --surf2:#EAECEF; --sunken:#E6E9ED;
    --line:#DDE0E5; --line2:#C8CDD5;
    --tx:#14161A; --tx2:#5E6672; --tx3:#626975;
    --amber:#FFB020; --amber-tx:#8A5300; --focus:var(--amber-tx); --amber-soft:rgba(255,176,32,.14);
    --green:#0E8F55; --shadow:rgba(20,22,26,.10);
  }
}
:root[data-theme="light"] {
  --bg:#F2F3F5; --surf:#FFFFFF; --surf2:#EAECEF; --sunken:#E6E9ED;
  --line:#DDE0E5; --line2:#C8CDD5;
  --tx:#14161A; --tx2:#5E6672; --tx3:#626975;
  --amber:#FFB020; --amber-tx:#8A5300; --focus:var(--amber-tx); --amber-soft:rgba(255,176,32,.14);
  --green:#0E8F55; --shadow:rgba(20,22,26,.10);
}

/* The Latin body stack, as a token because it is needed in two places now:
   `body` sets it, and `.prose strong` has to restate it in order to put a
   face with Arabic glyphs in front of it. Two literal copies of a stack is
   how one of them quietly stops matching the other. */
:root { --sans: "IBM Plex Sans", ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif; }

* { box-sizing: border-box; }
body {
  margin:0; background:var(--bg); color:var(--tx);
  font:400 16px/1.6 var(--sans);
  -webkit-font-smoothing:antialiased; overflow-x:hidden;
}
h1,h2,h3 { font-family:Archivo,"Helvetica Neue",Arial,sans-serif; letter-spacing:-.025em; text-wrap:balance; margin:0; }
p { margin:0; }
a { color:var(--amber-tx); text-decoration:none; }
a:hover { text-decoration:underline; }
main p a, main li a, main td a { text-decoration:underline; text-underline-offset:.15em; }
a:focus-visible, button:focus-visible, summary:focus-visible, .strip:focus-visible { outline:2px solid var(--focus); outline-offset:3px; border-radius:4px; }
/* Skip link: visually hidden until it takes keyboard focus, then a visible
   box in the top inline-start corner. Logical properties for RTL. */
.skip { position:absolute; inset-block-start:0; inset-inline-start:0; width:1px; height:1px; margin:-1px; padding:0; overflow:hidden; clip-path:inset(50%); white-space:nowrap; border:0; }
.skip:focus, .skip:focus-visible { width:auto; height:auto; margin:0; overflow:visible; clip-path:none; z-index:100; inset-block-start:.75rem; inset-inline-start:.75rem; padding:.6rem 1rem; background:var(--surf); color:var(--tx); border:2px solid var(--focus); border-radius:6px; font-weight:600; text-decoration:none; }
.shell { max-width:70rem; margin:0 auto; padding:0 1.5rem; }

/* ── eyebrow ───────────────────────────────────────────────────── */
.eyebrow { font-family:"IBM Plex Mono",monospace; font-size:.72rem; font-weight:500; letter-spacing:.16em; text-transform:uppercase; color:var(--tx3); }
.eyebrow .on { color:var(--amber-tx); }

/* ── plate rail divider ────────────────────────────────────────── */
.rail { height:3px; display:flex; align-items:center; }
.rail::before { content:""; flex:0 0 auto; width:34px; height:3px; background:var(--amber); }
.rail::after { content:""; flex:1 1 auto; height:1px; background:repeating-linear-gradient(to right, var(--line) 0 1px, transparent 1px 9px); }

/* ── site header ───────────────────────────────────────────────── */
header.top { border-bottom:1px solid var(--line); background:var(--bg); }
.top .shell { display:flex; align-items:center; justify-content:space-between; gap:1rem; height:64px; }
.wordmark { font-family:Archivo,sans-serif; font-weight:800; font-size:1.3rem; letter-spacing:-.03em; color:var(--tx); display:flex; align-items:baseline; gap:.5rem; }
.wordmark:hover { text-decoration:none; }
/* The footer writes the brand exactly as the header does, but with no rule
   of its own it inherited the page's Latin or Hebrew stack. Same alias, so
   it costs nothing. `.wordmark .ar` below is more specific and still wins
   in the header, where the size and colour differ too. */
.ar { font-family:"Hadid Arabic","IBM Plex Sans Arabic",sans-serif; }
.wordmark .ar { font-family:"Hadid Arabic","IBM Plex Sans Arabic",sans-serif; font-weight:500; font-size:.95rem; color:var(--amber-tx); direction:rtl; unicode-bidi:isolate; }
nav.top-nav { display:flex; gap:1.5rem; }
nav.top-nav a { color:var(--tx2); font-size:.9rem; font-weight:500; display:inline-block; padding-block:.35rem; }
nav.top-nav a:hover { color:var(--tx); text-decoration:none; }
nav.top-nav a[aria-current="page"] { color:var(--tx); box-shadow:0 2px 0 var(--amber); }
/* The switcher names each language in its own language, so on the English
   pages two of its three links are words this stack has no glyphs for --
   "עברית" measured 39.88px in the inherited body stack against 30.89px in
   Plex Sans Hebrew, i.e. a system face, on the one control this whole wave
   exists to add. The generator already writes `lang` on each of these
   links, so nothing new is needed to address them. On / and /help this
   fetches the Hebrew 400 file those pages otherwise would not need; that
   is one request, and the alternative is shipping the switcher in a face
   the rest of the site does not use. */
nav.top-nav a[lang="ar"] { font-family:"IBM Plex Sans Arabic",sans-serif; }
nav.top-nav a[lang="he"] { font-family:"IBM Plex Sans Hebrew",sans-serif; }
/* The Arabic is half the wordmark, not decoration -- the app ships in
   Arabic and the brand is حديد. It was hidden below 640px only to buy
   room for the nav; shrinking it one step buys the same room and keeps
   the name whole. */
/* ...and the row it sits in has to be allowed to become two rows. The nav
   was three links when this header was drawn; the language switcher adds
   one per language, and at 375px five links plus the wordmark no longer
   fit on one line. Every page scrolled sideways -- 2px in English, 35px in
   Arabic, 42px in Hebrew, whose switcher entry is the widest -- and a
   page that scrolls sideways on a phone is the first thing a store
   reviewer sees. `height:auto` is half the fix, not tidying: a wrapping
   row still pinned to 64px overflows downward instead. */
@media (max-width:640px) {
  .top .shell { flex-wrap:wrap; height:auto; row-gap:.35rem; padding-top:.7rem; padding-bottom:.7rem; }
  nav.top-nav { flex-wrap:wrap; gap:1.1rem; row-gap:.35rem; font-size:.85rem; }
  .wordmark { font-size:1.15rem; gap:.4rem; }
  .wordmark .ar { font-size:.85rem; }
}

/* ── the language switcher ─────────────────────────────────────── */
.lang { position:relative; flex:0 0 auto; }
.lang > summary {
  list-style:none; cursor:pointer; display:inline-flex; align-items:center; gap:.32rem;
  font-family:"IBM Plex Mono",monospace; font-size:.7rem; font-weight:500; letter-spacing:.08em;
  color:var(--tx2); border:1px solid var(--line2); border-radius:6px;
  padding:.3rem .5rem; transition:color 150ms ease, border-color 150ms ease;
}
.lang > summary::-webkit-details-marker { display:none; }
.lang > summary:hover { color:var(--tx); border-color:var(--amber); }
.lang > summary .chev { font-size:.6rem; color:var(--tx3); transition:transform 150ms ease; }
.lang[open] > summary { color:var(--tx); border-color:var(--amber); }
.lang[open] > summary .chev { transform:rotate(180deg); }
/* inset-inline-end, never right: on /ar/ and /he/ the menu must anchor to the
   reading edge, and the logical property does it with no second rule. */
.lang-menu {
  position:absolute; top:calc(100% + .4rem); inset-inline-end:0; z-index:5; min-width:9.5rem;
  background:var(--surf); border:1px solid var(--line2); border-radius:9px;
  box-shadow:0 14px 28px -12px var(--shadow); padding:.3rem; display:grid; gap:.1rem;
}
.lang-menu a {
  display:flex; align-items:baseline; justify-content:space-between; gap:.8rem;
  padding:.42rem .55rem; border-radius:6px; text-decoration:none; color:var(--tx2); font-size:.85rem;
}
.lang-menu a:hover { background:var(--surf2); color:var(--tx); }
.lang-menu a[aria-current] { color:var(--tx); background:var(--amber-soft); }
.lang-menu .code { font-family:"IBM Plex Mono",monospace; font-size:.64rem; letter-spacing:.1em; color:var(--tx3); }
@media (prefers-reduced-motion: reduce) {
  .lang > summary, .lang > summary .chev { transition:none; }
  a.store:hover { transform:none; transition:none; }
  .card { transition:none; transform:none; }
}

/* ── store buttons ─────────────────────────────────────────────── */
.stores { display:flex; flex-wrap:wrap; gap:.75rem; }
.store {
  display:inline-flex; align-items:center; gap:.7rem;
  padding:.7rem 1.15rem; border-radius:11px; border:1px solid var(--line2);
  background:var(--surf); color:var(--tx); min-height:52px;
  transition:transform 180ms ease, border-color 180ms ease;
}
.store .l1 { display:block; font-family:"IBM Plex Mono",monospace; font-size:.6rem; letter-spacing:.13em; text-transform:uppercase; color:var(--tx3); line-height:1.4; }
.store .l2 { display:block; font-family:Archivo,sans-serif; font-weight:600; font-size:1rem; line-height:1.25; letter-spacing:-.015em; }
/* Not yet published: no href, no hover lift, and it reads as unavailable
   rather than as a link that 404s a store reviewer. */
.store.pending { border-style:dashed; }
.store.pending .l2 { color:var(--tx2); }
a.store:hover { text-decoration:none; transform:translateY(-2px); border-color:var(--amber); }

/* ── hero ──────────────────────────────────────────────────────── */
.hero { padding:4.5rem 0 3.5rem; position:relative; }
.hero::before { content:""; position:absolute; inset:-40% 0 30% 25%; background:radial-gradient(ellipse at 70% 25%, var(--amber-soft), transparent 62%); pointer-events:none; }
.hero-grid { position:relative; display:grid; grid-template-columns:minmax(0,1.05fr) minmax(0,.95fr); gap:3.5rem; align-items:center; }
@media (max-width:900px) { .hero-grid { grid-template-columns:1fr; gap:2.8rem; } .hero { padding:3rem 0; } }
.hero h1 { font-size:clamp(2.4rem,6vw,3.9rem); font-weight:800; line-height:.99; margin:1rem 0 0; }
.hero h1 .quiet { color:var(--tx2); font-weight:600; }
.hero .lead { color:var(--tx2); font-size:1.1rem; max-width:30ch; margin-top:1.1rem; }
.hero .stores { margin-top:1.9rem; }
.hero .fineprint { margin-top:.95rem; color:var(--tx3); font-size:.85rem; }

/* ── phone ─────────────────────────────────────────────────────── */
.phone-stage { display:flex; justify-content:center; }
.phone { width:284px; border-radius:34px; padding:9px; background:linear-gradient(160deg,var(--line2),var(--surf)); box-shadow:0 32px 64px -22px var(--shadow); flex:0 0 auto; }
.screen { background:#14161A; border-radius:26px; overflow:hidden; color:#F0F2F5; font-size:13px; line-height:1.35; }
.phone.sm { width:236px; border-radius:29px; padding:7px; }
.phone.sm .screen { border-radius:22px; font-size:11.5px; }

.sc-bar { display:flex; justify-content:space-between; align-items:center; padding:11px 15px 9px; font-family:"IBM Plex Mono",monospace; font-size:9.5px; color:#6C7480; letter-spacing:.05em; }
.sc-head { padding:4px 15px 13px; display:flex; justify-content:space-between; align-items:flex-end; border-bottom:1px solid #2E333B; }
.sc-title { font-family:Archivo,sans-serif; font-weight:700; font-size:16px; letter-spacing:-.02em; }
.sc-sub { color:#6C7480; font-size:10.5px; margin-top:2px; }
.sc-body { padding:13px 12px 16px; display:grid; gap:9px; }
.ex-card { background:#1C1F25; border:1px solid #2E333B; border-radius:11px; overflow:hidden; }
.ex-name { padding:9px 12px; font-weight:600; font-size:12.5px; display:flex; justify-content:space-between; border-bottom:1px solid #2E333B; }
.ex-name span { color:#6C7480; font-weight:400; font-size:10.5px; font-family:"IBM Plex Mono",monospace; }
.setrow { display:grid; grid-template-columns:20px 1fr 1fr 26px; align-items:center; gap:7px; padding:8px 12px; border-bottom:1px solid #23272E; font-variant-numeric:tabular-nums; }
.setrow:last-child { border-bottom:0; }
.setrow .n { color:#6C7480; font-family:"IBM Plex Mono",monospace; font-size:10.5px; }
.setrow .v { color:#F0F2F5; font-family:"IBM Plex Mono",monospace; font-size:12.5px; }
.setrow .tick { color:#2BB673; font-size:13px; text-align:center; }
.setrow.active { background:rgba(255,176,32,.07); box-shadow:inset 2px 0 0 #FFB020; }
.setrow.active .v { color:#FFB020; }
.setrow.active .tick { color:#6C7480; }
.rest-pill { display:flex; align-items:center; justify-content:space-between; background:#23272E; border:1px solid #2E333B; border-radius:999px; padding:7px 14px; font-size:11px; color:#99A1AD; }
.rest-pill b { color:#FFB020; font-family:"IBM Plex Mono",monospace; font-variant-numeric:tabular-nums; font-weight:500; }

/* The three /app re-creations were redrawn 2026-09-01 against the real JSX
   after a review found them depicting controls, a chart type and a whole
   screen the app does not have. Everything below exists because some real
   piece of the app needed it; if a screen stops using one of these, delete
   it rather than leaving it behind. */

/* app/workout/active.tsx's own app bar: Leave on the left, the session name
   and elapsed time centred, Finish in the accent on the right. Not a
   title/subtitle/clock row, which is what the first pass drew. */
.sc-head.bar { align-items:center; }
.sc-head.bar .sc-title { font-size:13px; }
.sc-act { color:#99A1AD; font-size:10px; font-weight:600; flex:0 0 auto; }
.sc-act.go { color:#FFB020; font-weight:700; }

/* ExerciseBlock's real five-column row -- set number, LAST SESSION (a
   read-only ghost line, never a prefill), weight, reps, check -- plus the
   column legend above it. Both phones draw it: the home hero used to draw a
   simpler four-column row with inline unit labels and no Previous column,
   which is not a row the app has ever rendered. */
.setrow.five { grid-template-columns:14px minmax(0,1fr) 32px 26px 18px; }
.setrow.five .p { color:#6C7480; font-family:"IBM Plex Mono",monospace; font-size:9.5px; }
.setrow.five .v { text-align:center; }
.setrow.legend { padding-top:7px; padding-bottom:4px; border-bottom:0; }
.setrow.legend div { color:#6C7480; font-size:8px; font-weight:600; letter-spacing:.03em; text-transform:uppercase; white-space:nowrap; }
.setrow.legend div:nth-child(3), .setrow.legend div:nth-child(4) { text-align:center; }
.setrow.tail { border-bottom:0; }
/* PlateHint is a 10.5pt grey one-liner under the weight field, not a card,
   and its string never includes the bar weight. See src/components/PlateHint.tsx. */
.plate-hint { color:#6C7480; font-family:"IBM Plex Mono",monospace; font-size:9.5px; }
/* active.tsx's own "Add exercise": a plain bordered ghost row in body text,
   deliberately not the accent -- it must not compete with the set rows. */
.addex { border:1px solid #2E333B; border-radius:9px; padding:8px; text-align:center; font-size:11px; font-weight:700; }

/* active.tsx's app bar: minimise (⌄), the session name and elapsed time
   centred, the rest composer (⏱) and Finish. `Leave` is gone -- it became
   `workout-minimize` when the persistent bar above the tab bar took over
   discard, and `workout-rest-clock` has been unconditional since
   2026-09-10. */
.sc-act.glyph { font-size:13px; line-height:1; }
/* plan.tsx:290-305 -- a 34pt bordered square with a sparkles glyph, which
   took the place of the header's old spacer. Not a ghost: the Plan screen's
   header genuinely has a control on that side now. */
.sc-act.coach { border:1px solid #2E333B; border-radius:6px; width:18px; height:18px; display:flex; align-items:center; justify-content:center; color:#F0F2F5; font-size:9px; }
.sc-head.bar .sc-titleblock { flex:1; min-width:0; text-align:center; }

/* active.tsx's docked keypad (`workout-keypad-dock`, :4509). It renders
   only while a field is focused -- the SAME condition that gives the set
   row its amber wash (SetRow.tsx:347, `focusedField !== null`). So a mock
   drawing the wash without the dock draws a state the app cannot be in,
   which is exactly what this phone did until 2026-09-21. */
.dock { border-top:1px solid #2E333B; background:#1C1F25; padding:9px 10px 12px; display:grid; gap:7px; }
.dockhead { display:flex; align-items:center; justify-content:space-between; gap:8px; font-size:9.5px; color:#99A1AD; }
.dockhead b { color:#F0F2F5; font-weight:700; }
.dockhead .rpe { color:#FFB020; font-weight:700; flex:0 0 auto; }

/* Keypad.tsx's GRID (:81-86): 7 8 9 / 4 5 6 / 1 2 3 / . 0 Delete, beside a
   right column of -step, +step and a double-height Next carrying its own
   sublabel.

   direction:ltr is deliberate and is the ONLY such pin in this stylesheet.
   Every other mock element mirrors under [dir="rtl"] and should -- the app
   mirrors too, which is why .setrow.five has its own RTL overrides below.
   The keypad is the one place the app does NOT mirror: Keypad.tsx pins
   LTR_STYLE because numeric keypads read 7 8 9 across the top in every
   language, and mirroring would "put the loosest, most-tapped layout in the
   app in an order no lifter has ever practiced". .dockhead above is NOT
   pinned, because that row does mirror in the app. */
.keys { display:flex; gap:5px; direction:ltr; }
.keygrid { flex:1; display:grid; grid-template-columns:repeat(3,1fr); gap:5px; }
.keyside { width:46px; display:grid; grid-template-rows:repeat(4,1fr); gap:5px; }
.key { background:#23272E; border-radius:7px; padding:7px 0; text-align:center; font-size:13px; font-weight:700; font-variant-numeric:tabular-nums; }
.key.sm { font-size:8.5px; display:flex; align-items:center; justify-content:center; }
.key.next { grid-row:span 2; background:#FFB020; color:#14161A; display:grid; align-content:center; gap:1px; }
.key.next b { font-size:12px; font-weight:800; }
.key.next em { font-style:normal; font-size:8px; font-weight:700; opacity:.72; }

/* ChartCard + BarChart. The app has no SVG chart anywhere: BarChart.tsx is
   a flex row of Views, 58px tall with a 6px gap, filled in amber ink. */
.ch { padding:11px 12px 12px; display:grid; gap:9px; }
.ch-head { display:flex; align-items:flex-start; justify-content:space-between; gap:8px; }
.ch-head b { display:block; font-weight:700; font-size:11.5px; letter-spacing:-.02em; }
.ch-head span { display:block; color:#6C7480; font-size:9.5px; }
.ch-head .cv { font-family:Archivo,sans-serif; font-weight:800; font-size:16px; letter-spacing:-.04em; font-variant-numeric:tabular-nums; }
.bars { display:flex; align-items:flex-end; gap:4px; height:46px; }
.bars i { flex:1; background:#FFB020; border-radius:2px; }

/* progress.tsx's row cards: a label and a trailing value, repeated. Used by
   "Getting stronger" (lift -> verdict) and "Last trained" (muscle -> gap).
   Verdict colours are the app's own tokens: green #2BB673 up, red #F0565B
   down, tx2 #99A1AD held (verdictColor(), progress.tsx:124). */
.vrow { display:flex; align-items:baseline; justify-content:space-between; gap:8px; font-size:10.5px; }
.vrow > span:first-child { color:#F0F2F5; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.vrow .val { color:#99A1AD; flex:0 0 auto; font-variant-numeric:tabular-nums; }
.vrow .val.up { color:#2BB673; }
.vrow .val.down { color:#F0565B; }
.badge { color:#FFB020; font-weight:700; }

/* ChartCard draws an ⓘ beside the value for any card passing `onExplain`
   (ChartCard.tsx:102-118). Three of the four Progress cards do. */
.ch-val { display:flex; align-items:center; gap:5px; }
.ch-i { color:#6C7480; font-size:11px; flex:0 0 auto; }
.ch-line { font-size:10px; color:#F0F2F5; }

/* app/plan.tsx: seven day cards, each a day name, either the routines
   planned on it as removable chips or "Rest", and a dashed "+ Add routine".
   That is the whole screen -- it has six translation keys. */
.ex-card.day { padding:11px 12px; display:grid; gap:8px; }
.day-name { font-weight:700; font-size:12px; }
.day-chips { display:flex; flex-wrap:wrap; gap:6px; }
.pchip { display:inline-flex; align-items:center; gap:5px; background:#23272E; border-radius:8px; padding:4px 7px 4px 9px; font-size:10.5px; font-weight:600; }
.pchip b { color:#99A1AD; font-weight:400; font-size:11px; }
.prest { color:#6C7480; font-size:10px; }
.padd { border:1px dashed #2E333B; border-radius:8px; padding:6px; text-align:center; color:#FFB020; font-size:10px; font-weight:700; }

/* ── refusal strip ─────────────────────────────────────────────── */
.thesis { border-top:1px solid var(--line); border-bottom:1px solid var(--line); background:var(--sunken); }
.thesis .shell { padding-top:2.2rem; padding-bottom:2.2rem; }
.refusals { display:grid; grid-template-columns:repeat(2,1fr); gap:1.8rem; margin-top:1.2rem; }
@media (max-width:760px) { .refusals { grid-template-columns:1fr; gap:1.1rem; } }
.refusal h3 { font-size:1.2rem; font-weight:700; display:flex; align-items:center; gap:.6rem; }
.refusal h3::before { content:""; width:15px; height:2px; background:var(--amber); flex:0 0 auto; }
.refusal p { color:var(--tx2); font-size:.93rem; margin-top:.3rem; }

/* ── generic band ──────────────────────────────────────────────── */
section.band { padding:4rem 0; }
@media (max-width:760px) { section.band { padding:2.8rem 0; } }
.band-head { max-width:44ch; }
/* h1 and h2 identically: /app and /help open their band with the page's own
   <h1> (the document heading this wave had left them without), while a band
   further down a page is an <h2>. Same type either way -- the level says
   what the heading IS, not how big it looks. */
.band-head h1, .band-head h2 { font-size:clamp(1.7rem,3.2vw,2.3rem); font-weight:700; margin-top:.85rem; }
.band-head > p { color:var(--tx2); margin-top:.7rem; }

/* ── card grid (home summary) ──────────────────────────────────── */
.cards { display:grid; grid-template-columns:repeat(auto-fit,minmax(232px,1fr)); gap:1px; margin-top:2.2rem; background:var(--line); border:1px solid var(--line); border-radius:14px; overflow:hidden; }
.card { background:var(--surf); padding:1.4rem 1.3rem; transition:background 180ms ease; }
.card:hover { background:var(--surf2); }
.card .kicker { font-family:"IBM Plex Mono",monospace; font-size:.64rem; letter-spacing:.14em; text-transform:uppercase; color:var(--amber-tx); }
.card h3 { font-size:1.08rem; font-weight:700; margin-top:.5rem; }
/* The legal pages' summary cards title with a <p>, not an <h3>, so no h3
   comes before the first h2 (heading order). Same look as .card h3. */
.card .card-title { font-family:Archivo,"Helvetica Neue",Arial,sans-serif; letter-spacing:-.025em; text-wrap:balance; color:var(--tx); font-size:1.08rem; font-weight:700; margin-top:.5rem; }
.card p { color:var(--tx2); font-size:.9rem; margin-top:.35rem; }

/* ── /app: screens strip ───────────────────────────────────────── */
.strip {
  display:flex; gap:1.6rem; margin-top:2.4rem;
  overflow-x:auto; padding-bottom:1rem;
  scroll-snap-type:x mandatory;
  -webkit-overflow-scrolling:touch;
}
@media (min-width:1000px) { .strip { justify-content:center; overflow-x:visible; } }
/* align-content:start, because the three re-creations are no longer the
   same height. Without it the flex row stretches each .shot to the tallest,
   and a grid with auto rows spends that extra space on the rows themselves
   -- so the shorter phones grew an empty slab of bezel below their screen. */
.shot { margin:0; flex:0 0 auto; scroll-snap-align:center; display:grid; align-content:start; justify-items:center; gap:.85rem; }
.shot figcaption {
  font-family:"IBM Plex Mono",monospace; font-size:.68rem; letter-spacing:.13em;
  text-transform:uppercase; color:var(--tx3); text-align:center;
}

/* ── /app: the spec table ─────────────────────── */
.sheet { max-width:50rem; margin-top:2rem; display:grid; gap:2.4rem; }
.sheet h2 {
  font-family:"IBM Plex Mono",monospace; font-size:.7rem; font-weight:500;
  letter-spacing:.16em; text-transform:uppercase; color:var(--amber-tx);
  padding-bottom:.55rem; border-bottom:1px solid var(--amber);
}
.sheet dl { margin:0; display:grid; grid-template-columns:minmax(9rem,13rem) 1fr; }
.sheet dt { padding:.68rem 1.2rem .68rem 0; border-bottom:1px solid var(--line); font-weight:600; font-size:.93rem; }
.sheet dd { margin:0; padding:.68rem 0; border-bottom:1px solid var(--line); color:var(--tx2); font-size:.93rem; }
/* Two families, because this one rule sets two scripts: the /app feature
   sheet writes "English · العربية · עברית" inline. Plex Sans Arabic's
   faces are scoped to the Arabic ranges, so עברית matched none of them
   and fell straight through to `sans-serif` -- a system face, on all three
   /app pages, English included. Ranges make the order harmless: Arabic
   codepoints only ever match the first family, Hebrew only the second. */
.sheet .rtl { font-family:"IBM Plex Sans Arabic","IBM Plex Sans Hebrew",sans-serif; direction:rtl; unicode-bidi:isolate; }
@media (max-width:620px) {
  .sheet dl { grid-template-columns:1fr; }
  .sheet dt { padding:.7rem 0 .1rem; border-bottom:0; }
  .sheet dd { padding:0 0 .7rem; }
}

/* ── prose + Q&A ───────────────────────────────────────────────── */
.prose { max-width:62ch; display:grid; gap:1rem; margin-top:1.6rem; }
.prose p { color:var(--tx2); }
/* "Hadid Arabic" leads so the brand word in help.about.p4 gets a face with
   glyphs; the two script families and the Latin token behind it are what
   every other word here would have inherited anyway. The weight stays 600
   -- pinning it to 500 to match the alias would have de-emphasised the
   Hebrew and English <strong>s that share this rule. */
.prose strong { color:var(--tx); font-weight:600; font-family:"Hadid Arabic","IBM Plex Sans Hebrew",var(--sans); }
.qa { max-width:62ch; margin-top:1.6rem; border:1px solid var(--line); border-radius:14px; overflow:hidden; }
.qa > div { padding:1.15rem 1.3rem; background:var(--surf); border-bottom:1px solid var(--line); }
.qa > div:last-child { border-bottom:0; }
.qa h3 { font-size:1.02rem; font-weight:700; }
.qa p { color:var(--tx2); font-size:.94rem; margin-top:.3rem; }

/* ── contact block ─────────────────────────────────────────────── */
.contact { margin-top:2rem; max-width:62ch; border:1px solid var(--line2); border-inline-start:3px solid var(--amber); background:var(--surf); border-radius:12px; padding:1.3rem 1.4rem; }
.contact h3 { font-size:1.05rem; font-weight:700; }
.contact p { color:var(--tx2); font-size:.94rem; margin-top:.35rem; }
.contact .mail { display:inline-block; margin-top:.8rem; font-family:"IBM Plex Mono",monospace; font-size:1rem; font-weight:500; color:var(--amber-tx); }

/* ── closing CTA ───────────────────────────────────────────────── */
.close { padding:4rem 0; text-align:center; border-top:1px solid var(--line); }
.close h2 { font-size:clamp(1.8rem,4vw,2.6rem); font-weight:800; }
.close p { color:var(--tx2); margin-top:.7rem; }
.close .stores { justify-content:center; margin-top:1.7rem; }

/* ── footer ────────────────────────────────────────────────────── */
footer.site { border-top:1px solid var(--line); padding:2.2rem 0 3rem; color:var(--tx3); font-size:.88rem; }
footer.site .shell { display:flex; flex-wrap:wrap; gap:1.1rem; justify-content:space-between; align-items:center; }
footer.site nav { display:flex; flex-wrap:wrap; gap:1.3rem; }
footer.site nav a { color:var(--tx2); display:inline-block; padding-block:.35rem; }
/* The "the legal pages are English only" note, emitted on the ar and he
   pages only -- English has nothing to say there, so build.mjs omits the
   wrapper entirely rather than emit an empty element.
   It lives inside footer.site nav, which is a wrapping flex row of links, so
   without a rule of its own it lands as one more item in that row and reads
   as a nav link. flex-basis:100% takes it out of the links' flow onto its own
   line; --tx3 is the footer's own muted colour, a step back from the --tx2
   the links use, so it reads as a note rather than a destination.
   order:1 puts that line AFTER every link. Without it the note breaks the row
   where it sits in the markup -- just after Terms -- and strands the email
   address alone on a third line below it. Its DOM position stays next to the
   two links it is about, which is what a screen reader follows; nothing
   focusable is reordered, since the note is a plain <span>. */
.legal-note { order:1; flex-basis:100%; color:var(--tx3); }

/* privacy/ and terms/ keep their markup verbatim this wave -- these four
   selectors are theirs. Deleting them unstyles both pages silently. */
/* The same horizontal padding .shell carries -- 1.5rem, matching it exactly,
   not just in kind -- so the legal text starts at the same x as every other
   page rather than being the one exception. Without it the two legal pages
   -- the only pages that use .wrap -- ran their text to the screen edge on
   every phone, because `body` has no padding either: the rewrite moved that
   responsibility into .shell, and .wrap never inherited it. */
.wrap { max-width: 62ch; margin: 0 auto; padding: 0 1.5rem; }
/* The document heading both legal pages lost when the shared header replaced
   their <h1 class="brand"> with an <a class="wordmark">. Until this rule and
   the markup that goes with it, the string "Privacy Policy" appeared nowhere
   in the rendered page -- only in <title> -- and both documents' heading
   outlines started at <h2>. Play and Apple open these two pages. */
.wrap main > h1 { font-size: clamp(1.9rem, 4vw, 2.4rem); font-weight: 800; margin-bottom: 1.1rem; }
.lead { font-size: 1.1rem; color: var(--tx2); }
.note {
  background: var(--surf); border: 1px solid var(--line);
  border-inline-start: 3px solid var(--amber); border-radius: 6px;
  padding: .9rem 1.1rem; margin: 1.5rem 0; color: var(--tx2); font-size: .95rem;
}
.note strong { color: var(--tx); }
.updated { color: var(--tx3); font-size: .9rem; }
table { border-collapse: collapse; width: 100%; margin: 1rem 0; font-size: .95rem; }
th, td { text-align: start; padding: .6rem .75rem; border-bottom: 1px solid var(--line); vertical-align: top; }
th { color: var(--tx2); font-weight: 600; }

/* ── per-language type ────────────────────────────────────────── */
/* Archivo has no Arabic or Hebrew glyphs. Without this, every heading on an
   ar/he page silently falls back to a system face and the page stops looking
   like the rest of the site.

   `.sc-title` is in this list and is not a heading: it is the routine name
   inside the phone mock, and it names Archivo directly, so the h1/h2/h3
   redirect misses it. It sits in the hero of / and /app, which made it one
   of the most prominent words on the page and one of the only ones set in
   a system face. Measured: "סיום" was 23.02px in `Archivo, sans-serif` and
   23.02px in bare `sans-serif`, against 24.83px in Plex Sans Hebrew.
   Composing the Archivo family by unicode-range, the way "IBM Plex Mono" is
   composed at the top of this file, does NOT work for it -- Archivo has
   real 700 and 800 faces, and Chrome picks an exact-weight Latin face over
   a range-weight scoped one before unicode-range is ever consulted. */
html[lang="ar"] body,
html[lang="ar"] h1, html[lang="ar"] h2, html[lang="ar"] h3,
html[lang="ar"] .sc-title {
  font-family: "IBM Plex Sans Arabic", sans-serif;
}

html[lang="he"] body,
html[lang="he"] h1, html[lang="he"] h2, html[lang="he"] h3,
html[lang="he"] .sc-title {
  font-family: "IBM Plex Sans Hebrew", sans-serif;
}

/* Numerals stay mono in every language -- a weight figure is a figure. The
   Arabic glyphs behind that stack come from the composed @font-face at the
   top of this file, not from a system fallback. */
html[lang="ar"] .eyebrow, html[lang="he"] .eyebrow,
html[lang="ar"] .kicker, html[lang="he"] .kicker { font-family: "IBM Plex Mono", monospace; }

/* Tracking is a Latin device. Arabic is cursive, so `letter-spacing` does
   not put air between letters -- it stretches the joins, and the wide
   tracking these three labels carry made them read as though they had been
   padded with tatweel. Only the rules above .13em are reset; the mock's
   .05-.06em is inside the noise. Scoped to ar because Hebrew is not
   cursive and tracking is fine there. */
html[lang="ar"] .eyebrow,
html[lang="ar"] .kicker,
html[lang="ar"] .store .l1,
html[lang="ar"] .shot figcaption,
html[lang="ar"] .sheet h2 { letter-spacing: normal; }

/* The /app log mock's five-column set row opens with a 14px column, which is
   the exact width of the English legend header "Set" -- it was measured to
   fit and nothing else. The app's own Arabic word for that column is
   مجموعة (workout.set in src/i18n/ar.json), 26px at this 8px size, so on
   /ar/app the header overran its column and ran into "السابق" beside it:
   the two words rendered touching. The column widens; the cells under it
   hold "W", "1", "2" and do not care.

   Keyed on [dir="rtl"] rather than html[lang="ar"] because the fix is about
   the script's word lengths, not about Arabic specifically -- Hebrew lands
   in the same rule when Task 5 turns it on, and dir is now emitted on every
   page, so the hook is always there to key on. */
[dir="rtl"] .setrow.five { grid-template-columns:30px minmax(0,1fr) 32px 26px 18px; }

/* The active row's amber edge. `box-shadow` has no logical form, so the
   `inset 2px 0 0` on `.setrow.active` is a physical LEFT edge and stayed
   put when everything around it mirrored -- on /ar it sat on the row's
   trailing edge with the tick, opposite the set number it belongs to.
   src/components/SetRow.tsx marks the real row with `borderStartWidth` /
   `borderStartColor`, i.e. the START edge, so on an Arabic phone the accent
   is on the right; the mock has to agree with the app it is a picture of.
   Negative offset = the other side. */
[dir="rtl"] .setrow.active { box-shadow:inset -2px 0 0 #FFB020; }

/* ── legal pages: summary and contents ─────────────────────────── */
.summary { margin-top:1.3rem; }
.summary .lbl,
.toc .lbl { font-family:"IBM Plex Mono",monospace; font-size:.64rem; letter-spacing:.14em; text-transform:uppercase; }
.summary .lbl { color:var(--amber-tx); }
.toc .lbl { color:var(--tx3); }
.summary .foot { margin-top:.9rem; font-size:.82rem; color:var(--tx3); }
.toc { margin-top:1.3rem; border-top:1px solid var(--line); border-bottom:1px solid var(--line); padding:.9rem 0; }
.toc ol { margin:.6rem 0 0; padding:0; list-style:none; columns:2; column-gap:1.6rem; }
@media (max-width:620px) { .toc ol { columns:1; } }
.toc li { margin:.24rem 0; break-inside:avoid; }
.toc a { color:var(--tx2); text-decoration:none; font-size:.87rem; display:inline-flex; padding-block:.35rem; gap:.5rem; align-items:baseline; }
.toc a:hover { color:var(--amber-tx); }
.toc .n { font-family:"IBM Plex Mono",monospace; font-size:.66rem; color:var(--tx3); min-width:1.1rem; }
/* A jumped-to heading must not sit flush against the viewport top. */
.wrap main h2 { scroll-margin-top:1rem; }

/* ── replacements for former inline styles (the page CSP forbids style="") ── */
.rail.rail-wide { max-width:210px; }
.rail.rail-narrow { max-width:170px; }
.rail + .eyebrow { margin-top:1rem; }
.more-link { margin-top:1.6rem; }
section.band.band-flush-bottom { padding-bottom:0; }
section.band.band-tight-top { padding-top:2rem; }
h2.qa-heading { font-size:1.5rem; font-weight:700; margin-top:3rem; }
.bars i.h-54 { height:54%; }
.bars i.h-71 { height:71%; }
.bars i.h-63 { height:63%; }
.bars i.h-88 { height:88%; }
.bars i.h-46 { height:46%; }
.bars i.h-79 { height:79%; }
.bars i.h-92 { height:92%; }
.bars i.h-74 { height:74%; }
