/* Keyboardo — layout.css. Page grid, header/footer, ad slots (CONTRACTS §7),
   pre-hydration skeleton heights (zero load CLS), mobile-first breakpoints.
   Dense style: the 4 sheets share a 32 KB budget and comments ship. */

body{display:grid;grid-template-columns:minmax(0,1fr);align-content:start;min-height:100vh;max-width:1360px;margin-inline:auto;padding-inline:16px}

/* Logical inset, not `left`: in an RTL page the skip link must appear at the
   inline START (the right edge), where both a reader's eye and the reading
   order begin. With `left` it landed on the far side of an Arabic page. */
.skip-link{position:absolute;display:flex;align-items:center;min-block-size:44px;inset-inline-start:-9999px;top:0;z-index:200;background:var(--accent);color:var(--accent-text);padding:8px 14px;border-radius:0 0 var(--radius) var(--radius)}
.skip-link:focus-visible{inset-inline-start:16px}

/* --- Header ---
   The 24px ROW gap on the nav is a touch-target requirement, not decoration:
   each nav link carries a ::after hit-area overlay of inset-block:-12px
   (components.css §15), so two wrapped rows closer than 24px would have
   OVERLAPPING tap targets. The 16px column gap clears the -7px inline
   overlays with 2px to spare. Same reasoning for the footer nav. */
#site-header{display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;gap:8px 16px;padding-block:14px}
.logo{display:inline-flex;align-items:center;min-block-size:44px;font-size:1.4rem;font-weight:700;letter-spacing:.5px;color:var(--text)}
.logo:hover{color:var(--accent);text-decoration:none}
#site-header nav{display:flex;flex-wrap:wrap;align-items:center;gap:24px 16px;font-size:.875rem}
#site-header nav a{color:var(--sub)}
#site-header nav a:hover{color:var(--text);text-decoration:none}
#auth-nav{display:inline-flex;gap:16px;margin-inline-start:8px;padding-inline-start:16px;border-inline-start:1px solid var(--border)}

#app{width:100%;max-width:1000px;margin-inline:auto;padding-block:24px}

/* --- Pre-hydration skeleton: the server-rendered shell must occupy exactly
       the space the hydrated UI will. #words-wrap reserves exactly 3 lines.

       THESE NUMBERS TRACK THE CONTROL HEIGHTS and were re-derived when the
       keycap system landed (caps 32 -> 44px, #restart-btn 40 -> 56px):
         #menu-bar   44px -> 66px = 11px keyplate padding x2 + one 44px cap row
         #live-stats 2rem         = unchanged, it holds no controls
         #test-wrap  21rem -> 22.375rem (358px) = 48 padding + 48 (3x16 gap)
             + 32 live-stats + 153.6 words-wrap (3 x --test-line) + 56 restart
             cap + 19.5 hint. Mobile --test-line 2.4rem gives 319.7px -> 20rem
             (the old sheet had no mobile value and over-reserved by ~17px).
       Change a control height and these change in the same commit. --- */
#menu-bar{min-height:66px}
#live-stats{height:2rem}
#test-wrap{min-height:22.375rem}
#words-wrap{position:relative;height:calc(3 * var(--test-line));overflow:hidden;width:100%}

/* --- Ad slots (CONTRACTS §7). ads_enabled=false -> body.ads-off: collapsed.
       ads_enabled=true -> the fixed reserved heights below: zero CLS on fill.
       During a test JS sets body.test-active: visibility only, space kept. --- */
.ad-slot{display:flex;align-items:center;justify-content:center;overflow:hidden}
body.ads-off .ad-slot{display:none!important} /* must beat the #id display rules below */
body.test-active .ad-slot{visibility:hidden}
#ad-header{height:100px}   /* 320x100 mobile reservation */
#ad-sidebar{display:none}  /* desktop only (>=1200px) */
#ad-result{height:280px}   /* 336x280, inside the results screen */

#seo-content{width:100%;max-width:72ch;margin-inline:auto;padding-block:40px 24px}

/* --- Footer --- */
#site-footer{display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;gap:8px 16px;padding-block:20px;border-top:1px solid var(--border);color:var(--sub);font-size:.8125rem}
#site-footer nav{display:flex;flex-wrap:wrap;gap:24px 16px}
#site-footer nav a{color:var(--sub)}
#site-footer nav a:hover{color:var(--text);text-decoration:none}
#site-footer .footer-note{flex-basis:100%}
#theme-quick-toggle{font-size:1.1rem} /* it is a keycap; skin lives in components.css §1 */

/* --- Active-test dimming (cosmetic; the binding ad rule is visibility above) */
body.test-active #site-header,body.test-active #menu-bar,body.test-active #restart-hint,body.test-active #site-footer{opacity:.25;transition:opacity .2s}

/* --- Breakpoints (mobile-first) --- */
@media (max-width:600px){
:root{--test-font:1.5rem;--test-line:2.4rem}
#app{padding-block:12px}
#test-wrap{min-height:20rem} /* re-derived reserve for the shorter --test-line */
}
@media (min-width:768px){
#ad-header{height:90px} /* 728x90 desktop reservation */
}
@media (min-width:1200px){
body{grid-template-columns:minmax(0,1fr) 300px;column-gap:24px}
body.ads-off{grid-template-columns:minmax(0,1fr);column-gap:0}
#site-header,#ad-header,#seo-content,#site-footer{grid-column:1 / -1}
#app{grid-column:1}
#ad-sidebar{display:flex;grid-column:2;width:300px;height:250px;position:sticky;top:16px}
}
