/* ==========================================================================
   TYPE RHYTHM — the scale applied as a design decision
   assets/css/type-rhythm.css · loaded by inc/type-rhythm.php (LAST)

   OWNER (ET): See fail ei lisa poodi ühtki uut asja — ta paneb OLEMASOLEVA
   kirjasüsteemi korralikult tööle. Kolm nähtavat muudatust:
     1. Lehe suur pealkiri on kõikjal ÜHESUURUNE. Praegu on tal viis eri
        mõõtu (tooteleht 40px, poeleht 40px, sisuleht 44px, blogi arhiiv
        46px, blogi artikkel 50px) — edaspidi üks: kuni 44px.
     2. Pealkirjade tasemed hakkavad erinema. Praegu on H1, H2, H3 ja H4
        kõigil ühesugune reavahe ja ühesugune paksus, nii et pealkirja
        "tase" on näha ainult suurusest. Nüüd on igal tasemel oma reavahe
        ja oma paksus, nagu disainipakis kirjas.
     3. Tekstirida muutub loetava pikkusega. Tootekirjelduse lõik on
        arvutiekraanil praegu ~170 tähemärki laiune (silm kaotab rea lõpus
        järje); edaspidi ~70. Telefonis EI MUUTU midagi — seal on rida
        niikuinii lühike.
   Lisaks: numbrid ostukorvi ja kassa tabelites saavad ühelaiused numbrid,
   nii et summade tulp on joondatud ja arv ei nihku, kui 9 asendub 1-ga.
   Lülitub välja seadete lülitiga `type_rhythm` (vaikimisi sees).

   ── WHY THIS FILE EXISTS ────────────────────────────────────────────────
   assets/css/tokens.css ships 4 weights, 13 sizes, 13 line-heights and 14
   compound steps. The migration moved declarations onto the atoms, but the
   SCALE was never applied as a decision: which level is which, and what the
   rhythm between them is. Measured before writing (every claim has a line):

     · main.css:142 styles h1, h2, h3 and h4 in ONE rule — same
       letter-spacing (-.02em), same line-height (1.15), same weight (700).
       Four levels, one set of metrics. The pack gives each level its own:
       tokens.css:187 (--lh-h1 1.08 · --lh-h2 1.15 · --lh-h3 1.25 ·
       --lh-h4 26px) and tokens.css:200-203 (tracking -.02 / -.015 / -.01 /
       -.005em, weight 700 / 700 / 600 / 600).
     · One heading level, five clamps:
         woocommerce.css:71   .woocommerce-products-header__title  28→40
         woocommerce.css:652  .single-product .product_title       28→40
           (+ woocommerce.css:1625 rewrites it to 24→30 below 768px)
         pages.css:246        .page-article__title                 30→44
         blog.css:171         .blog-archive__title                 30→46
         blog.css:37          .blog-article__title                 30→50
         tokens.css:175       --fs-h1                              28→44
     · No measure anywhere in prose. Only two `ch` caps exist in the whole
       theme (tracking.css:21 and woocommerce.css:1102). The product
       description (.ostu-psec__body, inc/product-sections.php:162) sits in
       .container (main.css:151, max-width 1440, padding 24) — 1392px
       of running text at 16px, roughly 170 characters per line. The target
       is 60-75 on desktop, 35-60 on a phone.

   ── SPECIFICITY / ORDER (Trap 1) ────────────────────────────────────────
   This file is enqueued at wp_enqueue_scripts priority 100 with the theme's
   own stylesheets as dependencies, so it is the LAST theme sheet printed and
   an equal-specificity rule wins on source order. Three other modules also
   register above the usual 10/20 — surfaces-d4-d12.php at 98, motion.php at 99
   and choreography.php at 100 — and it is choreography.php's FILENAME, not a
   priority number, that keeps this file behind it: equal priorities run in
   add_action() order, which is functions.php's alphabetical glob of the inc
   directory.
   The full chain and what would break it are in inc/type-rhythm.php's header.
   Where a plugin sheet could
   outrank us the selector is written at the plugin's own shape as well —
   see the product title below, which carries both a (0,2,0) and a (0,4,1)
   form in one rule (a selector list is evaluated per selector, so both
   apply at their own weight).
   NOT VERIFIED IN A BROWSER: no browser was available. Specificity here is
   arithmetic on the files listed above, not a computed value read off a live
   page. Trap 1 says arithmetic can still lose — check the COMPUTED values.

   ── WHAT THIS FILE DELIBERATELY DOES NOT DO ─────────────────────────────
   · It declares NO custom property. Not one. Some 536 declarations already
     consume the atoms; redeclaring a token here would move all of them in a
     commit whose diff only says "added a file".
   · It does not touch the shop product name (woocommerce.css:145, 14.5px).
     Owner exception, README section 4 point 1. Do not "tidy" it.
   · It does not touch the 940px trust-bar breakpoint. Owner exception,
     README section 4 point 2.
   · It does not touch price colour or price size — the price cascade is a
     known open issue and belongs to whoever fixes it, not to this file.
   · It contains no animation and no transition, so there is nothing for
     prefers-reduced-motion to switch off. The state changes it makes are
     static type; nobody loses information with motion disabled.
   · It goes nowhere near the checkout gateway area (CLAUDE.md invariant 1).
     The one checkout selector below is a table CLASS, and
     font-variant-numeric inherits downward only — it cannot reach a sibling.
   ========================================================================== */


/* ==========================================================================
   1 · ONE H1 — the page's own title, one size everywhere
   --------------------------------------------------------------------------
   The compound token is the pack's default API (README section 5b point 3);
   the literal fallback after the comma is the stack that renders live today
   (main.css:103 wins --font-display over tokens.css:163 — see the report),
   so a zip that somehow shipped without tokens.css still renders correctly.

   Visible deltas at 1440px: product title 40→44, shop archive 40→44,
   content page 44→44, blog archive 46→44, blog article 50→44. On a 375px
   phone every one of them becomes 28px (the clamp floor); the product title
   was 26.25px there, so it grows by under 2px.

   text-wrap: balance is the whole reason a long Estonian product name stops
   leaving one orphaned word on its own line. Browsers that do not know the
   value ignore the declaration and nothing else changes.
   ========================================================================== */

.page-article__title,
.blog-article__title,
.blog-archive__title,
.woocommerce-products-header__title,
.woocommerce-products-header .woocommerce-products-header__title,
.single-product .product_title,
.single-product.woocommerce div.product .product_title {
  font: var(--h1, 700 clamp(28px, 4.4vw, 44px)/1.08 "Space Grotesk", "DM Sans", system-ui, sans-serif);
  letter-spacing: var(--h1-tracking, -.02em);
  text-wrap: balance;
}


/* ==========================================================================
   2 · FOUR LEVELS, FOUR RHYTHMS
   --------------------------------------------------------------------------
   Deliberately written on the BARE elements at (0,0,1). That is the point:
   this is the default layer. Every component that sets its own size keeps it
   — .ostu-psec__body headings stay 17px (product-sections.css:91, (0,1,1)),
   .page-article__content h2 stays 26px (pages.css:257), .blog-article__content
   h2 stays its own clamp (blog.css:60).

   ⚠️ THIS SECTION SETS font-size TOO, AND THAT IS A VISIBLE CHANGE — corrected
   2026-08-14, because the paragraph that used to stand here said the opposite.
   The old text read "What those rules do NOT set is leading, tracking and
   weight … so a heading now reads as a level even where the size is decided
   elsewhere", which describes a file that leaves size alone. This one does not:
   the four rules below declare `font-size` (lines 145, 153, 160, 167) as well
   as leading, tracking and weight.

   That matters because of what main.css:142 actually is. Read it:
     h1, h2, h3, h4 { font-family; letter-spacing: -.02em; line-height: 1.15;
                      color; font-weight: 700 }
   Five properties — and NOT font-size. It is the only bare-element heading rule
   in the theme (measured 2026-08-14 by parsing all 53 stylesheets in
   assets/css; print.css:68 is the only other bare h1-h4 selector and it sets
   margins inside @media print). So before this file existed, every heading with
   no size rule of its own rendered at the BROWSER DEFAULT, computed against
   body's 16px (main.css:120, --fs-md):
     h1 2em    = 32px      →  var(--fs-h1) = clamp(28px, 4.4vw, 44px)
     h2 1.5em  = 24px      →  var(--fs-h2) = clamp(24px, 3.2vw, 32px)
     h3 1.17em = 18.72px   →  var(--fs-h3) = clamp(20px, 2.2vw, 24px)
     h4 1em    = 16px      →  var(--fs-h4) = 18px
   So on a 375px phone nothing moves at h2 (24px both ways) while h3 gains
   ~1.3px and h4 gains 2px; on a 1440px desktop h2 goes 24→32px and h3 18.7→24px.
   That is a real, visible change to running content, not a metrics tidy-up.

   WHICH HEADINGS KEEP THEIR OWN SIZE. These are every rule in assets/css that
   gives an h1-h4 a font-size — all of them class-based, (0,1,1) or heavier, so
   all of them beat this section's (0,0,1) and none of them moves:
     blog.css                .blog-article__content h2 / h3 / h4
     pages.css               .page-article__content h2 / h3 / h4
     product-sections.css:89 .ostu-psec__body :is(h1, h2, h3, h4)
     single.css:365          .related.products > h2
     woocommerce.css         .related/.upsells.products > h2, .woocommerce-tabs
                             .panel h2, .cart_totals h2, #customer_login h2,
                             .woocommerce-billing-fields h3 (+ shipping,
                             additional), .woocommerce-Address-title h3
     cart-polish.css         .cart-collaterals .cart_totals h2
     checkout-polish.css     .woocommerce-billing-fields > h3
     main.css:—              .home-cta__inner h2
   plus section 1 of this file, which owns the five page-title classes.

   EVERY OTHER h1-h4 ON THE SITE MOVES — theme modules that never styled a
   heading size (My Account, wishlist, compare, gift cards, order tracking,
   trust band, the proof block) and any heading typed into page or post content.
   Not enumerable from CSS alone and NOT verified in a browser: this session had
   none. The owner should look at a content page, the blog, a My Account panel
   and the product page's own sections at phone and desktop width before this
   ships. The checkout is fenced out of all four rules (see the :where() below)
   and is unaffected either way.

   The audible change in the metrics is at H3: 700/-.02em/1.15 becomes
   600/-.01em/1.25. A block heading stops competing with a section heading.
   ========================================================================== */

/* text-wrap: balance is SCOPED, not global — and this is the one place where
   being thorough would have been the wrong answer. A bare h2 is also the
   product-card title (woocommerce.css:145): up to 48 of them on one archive
   page, each with a -webkit-line-clamp on its inner span
   (woocommerce.css:163) and a card height reserved from that clamp
   (min-height 38px, woocommerce.css:153). Re-balancing 48 clamped two-line
   titles is both a layout interaction I cannot verify without a browser and
   work a phone should not be asked to do (PageSpeed 91 is an asset).
   Balance belongs where headings are few and long: the page title above, and
   prose. */
.page-article__content :is(h2, h3, h4),
.blog-article__content :is(h2, h3, h4),
.ostu-psec__body :is(h2, h3, h4) {
  text-wrap: balance;
}

:where(body:not(.woocommerce-checkout):not(.woocommerce-add-payment-method)) h1 {
  font-size: var(--fs-h1, clamp(28px, 4.4vw, 44px));
  line-height: var(--lh-h1, 1.08);
  letter-spacing: var(--h1-tracking, -.02em);
  font-weight: var(--fw-bold, 700);
  text-wrap: balance;
}

:where(body:not(.woocommerce-checkout):not(.woocommerce-add-payment-method)) h2 {
  font-size: var(--fs-h2, clamp(24px, 3.2vw, 32px));
  line-height: var(--lh-h2, 1.15);
  letter-spacing: var(--h2-tracking, -.015em);
  font-weight: var(--fw-bold, 700);
}

:where(body:not(.woocommerce-checkout):not(.woocommerce-add-payment-method)) h3 {
  font-size: var(--fs-h3, clamp(20px, 2.2vw, 24px));
  line-height: var(--lh-h3, 1.25);
  letter-spacing: var(--h3-tracking, -.01em);
  font-weight: var(--fw-semibold, 600);
}

:where(body:not(.woocommerce-checkout):not(.woocommerce-add-payment-method)) h4 {
  font-size: var(--fs-h4, 18px);
  line-height: var(--lh-h4, 26px);
  letter-spacing: var(--h4-tracking, -.005em);
  font-weight: var(--fw-semibold, 600);
}


/* ==========================================================================
   3 · MEASURE — the line length a person can actually read
   --------------------------------------------------------------------------
   Three prose containers, all confirmed in the templates:
     .page-article__content      page.php:159  (also carries .entry-content)
     .blog-article__content      single.php:77
     .ostu-psec__body            inc/product-sections.php:162 and :168
   The short description on the product page is included because it is the
   same kind of copy (single.css:49).

   NOT INCLUDED, on purpose: .woo-page__content (page.php:132). page.php:107
   says in as many words that cart, checkout and account render full width
   with no prose measure, because My Account's nav + content need the room.
   A measure there would undo a decision somebody already paid for. This is
   also why the selector list names classes and never .entry-content on its
   own — the homepage is Elementor and must stay out of this.

   Why 68ch and not a pixel value: ch is the width of "0" in the CURRENT
   font, so one number is right for the 16px product description, the 17px
   content page and the 18px blog post. In DM Sans it lands at roughly 70
   characters per line — inside the 60-75 target.

   Below about 900px the container is already narrower than 68ch, so this
   rule does nothing on a phone: 339px of text at 16px (375 minus the 18px
   padding main.css:480 sets below 768) is ~42 characters,
   already inside the 35-60 phone target. max-width only ever shrinks a
   block, so no layout can be pushed wider by any of this.

   text-wrap: pretty stops a paragraph ending in a single word on its own
   line. Ignored where unsupported.
   ========================================================================== */

.page-article__content :is(p, ul, ol),
.blog-article__content :is(p, ul, ol),
.ostu-psec__body :is(p, ul, ol),
.single-product .woocommerce-product-details__short-description :is(p, ul, ol) {
  max-width: 68ch;
}

.page-article__content p,
.blog-article__content p,
.ostu-psec__body p,
.single-product .woocommerce-product-details__short-description p {
  text-wrap: pretty;
}

/* Tables and multi-column blocks set their own width — a measure inside a
   cell or a Gutenberg column would fight the layout instead of helping it.
   (0,2,1) so it beats the rule above at (0,1,1). */
.page-article__content :is(td, th, .wp-block-column, .wp-block-table) :is(p, ul, ol),
.blog-article__content :is(td, th, .wp-block-column, .wp-block-table) :is(p, ul, ol),
.ostu-psec__body :is(td, th, .wp-block-column, .wp-block-table) :is(p, ul, ol) {
  max-width: none;
}


/* ==========================================================================
   3b · RHYTHM — a heading belongs to what comes after it
   --------------------------------------------------------------------------
   Only ONE container needs this, and it is measured, not assumed:

     .page-article__content (pages.css:256) sets `> * + * { margin-top: 1.1em }`
     and pages.css:257 gives h2 `margin-top: 1.6em`. So the gap UNDER a
     heading (1.1em of 17px = 18.7px) is exactly the gap between two ordinary
     paragraphs. The heading floats equidistant between the section it closes
     and the section it opens, and the eye cannot tell which text it belongs
     to. That is the defect.

   The other two containers already have it right and are left alone:
     .blog-article__content — blog.css:60-63: heading margin-bottom .6em
       (~19px) against 1.4em (~25px) between paragraphs and 1.8em above.
     .ostu-psec__body — product-sections.css:94: `margin: 30px 0 10px`
       against 12px between paragraphs.
   Calm everywhere else is a design decision too.

   (0,1,1) beats the `> * + *` rule at (0,1,0). Space above the heading is
   untouched, so the ratio becomes roughly 3.4 : 1.
   ========================================================================== */

.page-article__content :is(h1, h2, h3, h4) + * {
  margin-top: var(--space-12, 12px);
}


/* ==========================================================================
   4 · NUMBERS THAT SIT IN A COLUMN
   --------------------------------------------------------------------------
   Money in a table is a column of digits, and proportional digits make that
   column ragged: the total shifts sideways when a quantity turns 9 into 1.
   The pack draws all three price steps with tabular figures (the A3 section
   of the designer sample marks every price row font-variant-numeric:
   tabular-nums), and about forty individual declarations across the theme
   already do it one element at a time — cart-sticky-bar.css:117 even carries
   the note about the `font` shorthand resetting it. What was missing is the
   TABLES: whole columns of numbers with nothing set.

   font-variant-numeric inherits, so one declaration on the table covers
   every cell in it — and, just as importantly, cannot reach anything that is
   not inside that table. The checkout review table below is a sibling of the
   gateway area, never a parent of it (CLAUDE.md invariant 1).

   These rules are placed AFTER every `font` shorthand in this file on
   purpose: the shorthand resets font-variant-numeric and font-feature-settings
   to their initial values, so the same declarations written above it would
   silently do nothing.
   ========================================================================== */

.woocommerce-cart-form .shop_table,
.cart_totals table,
.woocommerce-checkout-review-order-table,
.woocommerce-orders-table,
.woocommerce-table--order-details,
.woocommerce-table--order-downloads,
.woocommerce-MyAccount-content table.shop_table {
  font-variant-numeric: tabular-nums lining-nums;
  font-feature-settings: "tnum" 1, "lnum" 1;
}

/* Every price the shop prints, wherever it prints it. .woocommerce-Price-amount
   is WooCommerce's own span class, so this is one rule instead of the next
   forty one-offs. */
.woocommerce-Price-amount {
  font-variant-numeric: tabular-nums lining-nums;
  font-feature-settings: "tnum" 1, "lnum" 1;
}

/* The quantity box: the number a shopper actually edits, and the one that
   visibly jumps when its width changes under the caret. */
.woocommerce .quantity .qty {
  font-variant-numeric: tabular-nums lining-nums;
  font-feature-settings: "tnum" 1, "lnum" 1;
}


/* ==========================================================================
   END. Four moments, and calm everywhere else.

   Things that were measured and DELIBERATELY not changed here, so the next
   person does not have to measure them again:

   · The section heading (H2) has the same problem the page title had —
     .home-section__title (main.css:246) and .home-proof__title
     (home-proof.css:56) are clamp(24, 3.5vw, 36) while --fs-h2
     (tokens.css:176) is clamp(24, 3.2vw, 32). Left alone: those two
     surfaces are being designed in this same pass and a 4px change made
     from a different file would land on top of somebody's decision rather
     than next to it. It is a lead call, not a typographer's.
   · .ostu-wl-page__title (wishlist.css:126), .ostu-cmp-page__title
     (wishlist.css:275) and .ostu-track-form-wrap__title (tracking.css:20)
     are page-level H1s carrying yet more clamps (34 / 34 / 30). Same
     reason.
   · The shop product name is 500 weight at 14.5px/1.35 (woocommerce.css:145)
     while the pack's own exception (tokens.css:68) writes it 400 at
     14.5px/20px. The 14.5px is an owner exception and is safe; the weight
     and the leading disagree with the pack, and the card's reserved height
     (min-height 38px, woocommerce.css:153) is calculated from 1.35. Moving
     the leading to 20px makes two lines 40px and breaks that reservation —
     which is precisely the recalculation README section 4 says is not being
     done. Report, do not touch.
   ========================================================================== */
