/* ================================================================
   STYLE.CSS — all styling for the Bayit dashboard
   ----------------------------------------------------------------
   MAP OF THIS FILE (sections appear in this order):
     1 · FONTS & DESIGN TOKENS  — typefaces, sizes, colors, spacing
     2 · PAGE & SHELL           — gray page, black shell, toolbar row
     3 · FULLSCREEN MODE
     4 · TOOLBAR BUTTONS & POPUPS (share / year-export dialogs)
     5 · LOCATION (ZIP) OVERLAY
     6 · THE SCREEN             — the white dashboard card itself
     7 · TOP BAR                — location, parsha, battery
     8 · LEFT COLUMN            — clock, dates, Zmanim/Shabbos/Upcoming
     9 · RIGHT COLUMN           — HaYom Yom and the Omer block
    10 · LEARNING BAR           — Chumash…Daf Yomi strip at the bottom
    11 · SMALL-SCREEN LAYOUTS   — narrow landscape, portrait, phones
    12 · LOADING SPLASH
    13 · TYPE WEIGHTS & PNG-CAPTURE TWEAKS
    14 · MONTH CALENDAR OVERLAY (yc-…)
   ================================================================ */

/* ================================================================
   1 · FONTS & DESIGN TOKENS
   ================================================================ */
/* Fonts are shipped locally under /fonts/ so the page and the PNG
   export render identically on every machine. */
@font-face{font-family:'NotoSerif';font-style:normal;font-weight:400;font-display:swap;src:url('/fonts/NotoSerif-Regular.ttf') format('truetype');}
@font-face{font-family:'NotoSerif';font-style:normal;font-weight:600;font-display:swap;src:url('/fonts/NotoSerif-SemiBold.ttf') format('truetype');}
@font-face{font-family:'NotoSerif';font-style:normal;font-weight:700;font-display:swap;src:url('/fonts/NotoSerif-Bold.ttf') format('truetype');}
@font-face{font-family:'NotoSerif';font-style:normal;font-weight:800;font-display:swap;src:url('/fonts/NotoSerif-ExtraBold.ttf') format('truetype');}
@font-face{font-family:'NotoSerif';font-style:normal;font-weight:900;font-display:swap;src:url('/fonts/NotoSerif-Black.ttf') format('truetype');}
@font-face{font-family:'NotoSerifHebrew';font-style:normal;font-weight:400;font-display:swap;src:url('/fonts/NotoSerifHebrew-Regular.ttf') format('truetype');}
@font-face{font-family:'NotoSerifHebrew';font-style:normal;font-weight:700;font-display:swap;src:url('/fonts/NotoSerifHebrew-Bold.ttf') format('truetype');}
@font-face{font-family:'NotoSerifHebrew';font-style:normal;font-weight:800;font-display:swap;src:url('/fonts/NotoSerifHebrew-ExtraBold.ttf') format('truetype');}
@font-face{font-family:'NotoSerifHebrew';font-style:normal;font-weight:900;font-display:swap;src:url('/fonts/NotoSerifHebrew-Black.ttf') format('truetype');}
:root{
  /* Typography · Fonts — Noto Serif + Noto Serif Hebrew, self-hosted
     via @font-face above. Noto Serif Hebrew is listed after Noto Serif
     on the English stacks so mixed-script labels (e.g. Chabad Yomei
     d'Pagra rows rendered in generic body-text spans) pick up the
     right Hebrew glyphs instead of falling through to the platform's
     default system font. */
  --font-display:'NotoSerif','NotoSerifHebrew',serif;
  --font-body:'NotoSerif','NotoSerifHebrew',serif;
  --font-hebrew:'NotoSerifHebrew',serif;
  /* Typography · Sizes — expressed in cqi so they ride the .screen's
     inline-size container query at the design grid width (1872 px),
     wrapped in clamp() with a minimum floor so they stay readable
     when the screen container shrinks below ~1000 px (phone portrait,
     narrow preview windows). At native 1872 the cqi value is in the
     middle of each clamp range; at viewport widths below ~700 px the
     floor takes over so body text stays at 15 px / section titles at
     17 px / clock at 36 px and the body-tier elements stay uniform. */
  --content-size:clamp(15px, 1.625cqi, 60px);
  --content-line-height:1.5;
  --section-title-size:clamp(17px, 1.875cqi, 70px);
  --hdate-size:clamp(20px, 2cqi, 80px);
  --edate-size:clamp(20px, 2cqi, 80px);
  --occasion-size:clamp(13px, 1.5cqi, 50px);
  --topbar-brand-size:clamp(18px, 4cqi, 150px);
  --topbar-loc-size:clamp(11px, 1.125cqi, 40px);
  --topbar-parsha-size:clamp(22px, 4cqi, 130px);
  /* Colors */
  --screen-bg:#fff;
  --screen-fg:#000;
  --topbar-bg:#c5c5c5; /* NOT just the old top bar: the month grid separator lines and Shabbos/holiday cell shading use this gray. The three headers opt out with their own background:transparent. */
  --topbar-fg:#000;
  --accent:#000;
  --rule-color:#dcdcdc;
  --divider-color:#dcdcdc;
  /* Almanac ink scale — the quiet grays the day view is set in */
  --alm-ink:#161616;
  --alm-muted:#767676;
  --alm-faint:#9a9a9a;
  --alm-hair:#e2e2e2;
  /* CHROME TOKENS — the almanac-paper skin for the page AROUND the
     screen (same palette as account.html). Consumed ONLY by chrome
     selectors (html/body/.wrap/.info-panel/.shell/.nav/.nb/.dp-pop/
     .zip-*) — NEVER by .screen or anything inside it. The light/dark/
     by-sunset theme swaps these under html[data-theme="dark"]; since
     no rule inside .screen reads them (screen colors are the
     screen/alm/topbar token families above plus literals), the
     captured dashboard is unaffected by theme by construction —
     verified byte-identical against the committed reference PNGs. */
  --chrome-paper:#e8dfc8;
  --chrome-vig-a:#f1e9d6;
  --chrome-vig-b:#e2d8bf;
  --chrome-card:#faf6ec;
  --chrome-ink:#201d15;
  --chrome-muted:#7a715c;
  --chrome-hair:#ddd2b6;
  --chrome-field:#fffdf6;
  --chrome-field-line:#cabf9f;
  --chrome-shell:#f5efdf;      /* device bezel — pale card stock (light) */
  --chrome-shell-fg:#201d15;   /* text/icons on the bezel */
  --chrome-btn-line:#b9ae90;   /* toolbar button/pill borders */
  --chrome-btn-hover:rgba(32,29,21,0.07);
  --chrome-active:#c9932b;     /* amber ring — open popup / focus */
  --chrome-bad:#a4442f;
  --bg:var(--chrome-paper);
  --shell-bg:var(--chrome-shell);
  /* Layout & Spacing */
  --left-panel-width:45%;
  --topbar-height:9.45%;
  --left-padding:2.5%;
  --right-padding:2.5%;
  --section-gap:2.2%;
  /* Uniform gap between any section label (Zmanim / Shabbos / Upcoming /
     Omer / HaYom-Yom / Adar part labels) and the content directly under
     it. em-based so it reads the same in the L and R columns and scales
     with the panel. */
  --label-gap:0.5em;
  --zman-row-pad:0.5%;
  --shabbos-row-pad:0.5%;
  --learn-bar-pad:1.8%;
  /* Rules & Borders */
  --rule-weight:2.25px;
  /* THE dotted separator — one shared definition (Joseph's ruling) for
     every dotted rule on the screen, horizontal AND vertical: the
     zmanim/shabbos/upcoming ledger baselines, the topbar and learn-bar
     rules, the learn-bar item dividers, the Omer top rule and the
     L/R column divider all paint from these four tokens, so their dot
     size and gap rhythm are identical by construction and cannot
     drift. CSS `dotted` borders were dropped deliberately: the browser
     refits the dot pattern to each border's length (a 720px baseline
     and a 900px divider got different dot/gap sizes on the same page —
     the divider read visibly denser than the row baselines), while a
     repeating gradient keeps one fixed rhythm everywhere. */
  --sep-weight:var(--rule-weight);  /* line thickness */
  --sep-dot:var(--rule-weight);     /* dot length along the line */
  --sep-gap:var(--rule-weight);     /* gap between dots */
  --divider-weight:1px;
  --screen-radius:26px;
  --shell-radius:40px;
  --tb-radius:25px;
}
/* The derived dotted-separator painters. ONE definition — but declared
   on BOTH :root and .screen.e-paper-capture, deliberately: a custom
   property resolves its inner var()s where it is DECLARED, so a :root-
   only declaration would bake in the :root knob values and the capture
   block's --sep-dot/--sep-gap overrides would never reach the painters.
   Re-declaring the same text on the capture scope makes the substitution
   re-run there with the capture knobs. Plain (non-repeating) gradients
   tiled via background-size + background-repeat: html2canvas — the PNG
   capture path — does not implement repeating-linear-gradient, but
   tiles a plain linear-gradient correctly. */
:root,.screen.e-paper-capture{
  --sep-period:calc(var(--sep-dot) + var(--sep-gap));
  --sep-dots-h:linear-gradient(to right,var(--alm-hair) 0,var(--alm-hair) var(--sep-dot),transparent var(--sep-dot),transparent 100%);
  --sep-dots-v:linear-gradient(to bottom,var(--alm-hair) 0,var(--alm-hair) var(--sep-dot),transparent var(--sep-dot),transparent 100%);
}
/* Night chrome — applied by the inline theme script in index.html as
   data-theme on <html> (localStorage 'bayit_theme': light/dark/sunset,
   set from the /account Appearance control). ONLY the --chrome-*
   tokens change; no .screen-affecting variable appears here. */
html[data-theme="dark"]{
  --chrome-paper:#363024;
  --chrome-vig-a:#484230;
  --chrome-vig-b:#2c2619;
  --chrome-card:#5c5544;
  --chrome-ink:#f2ecdf;
  --chrome-muted:#c6bc9a;
  --chrome-hair:#67604d;
  --chrome-field:#413b2d;
  --chrome-field-line:#726b57;
  --chrome-shell:#4c4536;      /* bezel — warm brown, a step above the paper */
  --chrome-shell-fg:#f2ecdf;
  --chrome-btn-line:rgba(242,236,223,0.45);
  --chrome-btn-hover:rgba(242,236,223,0.12);
  --chrome-active:#d8a545;
  --chrome-bad:#e0917f;
}

/* ================================================================
   2 · PAGE & SHELL — gray page, black shell, toolbar row
   ================================================================ */
html,body{
  background:var(--bg);color:#000;
  /* Prevent iOS Safari from auto-inflating text inside text-heavy blocks
     (notably .hy-text). Without this, the HaYom-Yom body renders larger on
     iPhone landscape than on desktop at the same --ui-scale. */
  -webkit-text-size-adjust:100%;
  text-size-adjust:100%;
}

*{box-sizing:border-box;margin:0;padding:0;}
body{background:var(--bg);min-height:100vh;font-family:var(--font-body);}
/* Paper vignette (same recipe as account.html) so the cream reads as
   printed stock, not flat fill. Chrome-only: .screen paints its own
   opaque --screen-bg above this. */
.wrap{min-height:100vh;background:var(--bg);background-image:radial-gradient(120% 80% at 50% -10%,var(--chrome-vig-a) 0%,var(--chrome-paper) 55%,var(--chrome-vig-b) 100%);display:flex;flex-direction:column;align-items:center;justify-content:center;padding:20px;gap:12px;}
/* Shell — responsive, sized by its container up to a reasonable reading
   width. The E1003's 4:3 native (1872×1404) is preserved via aspect-ratio
   on the screen; the on-screen rendering scales with available width. */
/* Gray page background + black shell rim with rounded corners. Shell
   padding (14px) + screen radius (14px) = shell radius (28px) — keeps
   the bezel visually concentric around the inner white card. Drop-shadow
   stack uses a subtle close shadow plus a wide ambient shadow for depth
   against the gray page. */
/* Shell width = the E1003 panel's PHYSICAL size + the 14px rim. The
   1872x1404 @ 227 PPI glass is 8.2467in x 6.185in. CSS "in" (96px)
   understates real inches on Mac/iPad displays, which render ~124 CSS
   px per physical inch - so the screen targets 8.2467 x 124 = 1023px
   (+ 28px rim). Measures true-to-glass on Apple hardware; smaller
   windows still shrink it responsively. */
.shell{width:100%;max-width:1051px;background:var(--shell-bg);border-radius:var(--shell-radius);padding:14px;box-shadow:0 2px 8px rgba(60,48,20,0.12),0 24px 60px rgba(70,56,24,0.22);}
/* Vertical padding zeroed on top, matched to shell padding on bottom so the
   black space above the nav (shell padding) visually equals the black space
   below the nav row before the white screen — keeps the menu icon and brand
   centered within the visible black band. */
.nav{display:flex;align-items:center;justify-content:flex-start;gap:8px;padding:0 16px 14px;flex-wrap:nowrap;}
.nav-toggle{flex:0 0 auto;}
.nav-items{display:flex;align-items:center;gap:8px;flex-wrap:nowrap;}
.nav-items[hidden]{display:none;}
/* Brand strip on the right side of the nav (the empty black area past
   the action buttons). Pushes itself to the right with margin-left:auto
   on desktop. On mobile the @media block switches it to a full-width
   second row so it sits below the buttons when space runs out. */
.nav-brand{margin-left:auto;color:var(--chrome-shell-fg);font-family:var(--font-body);font-size:18px;font-weight:700;letter-spacing:0.3px;display:inline-flex;align-items:center;gap:10px;white-space:nowrap;flex-shrink:0;}
.nav-brand-heb,.nav-brand-bh{font-family:var(--font-hebrew);font-weight:700;}
.nav-brand-dot{opacity:0.6;font-weight:400;}
/* Build number — small faint chip after the brand so the live version is
   verifiable at a glance. Lives in the toolbar chrome, so it never
   appears in the captured PNG. */
.build-tag{font-family:var(--font-body);font-size:11px;font-weight:600;letter-spacing:0.3px;opacity:0.55;color:var(--chrome-shell-fg);padding:1px 6px;border:1px solid var(--chrome-btn-line);border-radius:10px;}
/* Subtle hint line in the black chrome between the nav and the .screen.
   Lives outside .screen so it never appears in the PNG download. Tells
   browser users which dashboard items are interactive — most important
   is the daily-learning row, which is highlighted via <strong>. */
/* Toggleable interactive-items info panel. Sits OUTSIDE the shell, on
   the gray page background above it, so the dashboard chrome stays
   focused on the dashboard itself and the help text never bleeds into
   the PNG export. <details> is the native disclosure widget — closed
   it shows a one-line headline pointing at the most important
   affordance (the daily learning row); open it lists every clickable
   thing on the dashboard. */
.info-panel{width:100%;max-width:960px;background:var(--chrome-card);border:1px solid var(--chrome-hair);border-radius:12px;color:var(--chrome-ink);font-family:var(--font-body);font-size:13px;line-height:1.5;box-sizing:border-box;box-shadow:0 1px 1px rgba(60,48,20,.04),0 14px 34px rgba(70,56,24,.07);}
.info-panel summary{cursor:pointer;list-style:none;padding:10px 14px;display:flex;align-items:baseline;justify-content:center;gap:.4em;flex-wrap:wrap;text-align:center;}
.info-panel summary::-webkit-details-marker{display:none;}
.info-panel summary strong{font-weight:700;}
.info-more{opacity:0.65;font-size:12px;font-weight:500;letter-spacing:0.3px;}
.info-more::before{content:"▾ ";}
.info-panel[open] .info-more::before{content:"▴ ";}
.info-body{padding:2px 18px 14px;}
.info-body p{margin-bottom:6px;}
.info-body ul{list-style:none;display:flex;flex-direction:column;gap:6px;}
.info-body li{padding-left:1em;text-indent:-1em;}
.info-body li::before{content:"· ";opacity:0.55;}
.info-body strong{font-weight:700;}
/* ================================================================
   3 · FULLSCREEN MODE — .is-fullscreen strips the page chrome
   ================================================================ */
/* The fullscreen button swaps its icon once fullscreen is active. */
#fs-btn .fs-ico-exit{display:none;}
body.is-fullscreen #fs-btn .fs-ico-enter{display:none;}
body.is-fullscreen #fs-btn .fs-ico-exit{display:inline;}
/* Fullscreen mode — strip the page chrome around the shell so the
   dashboard fills the viewport and hide the info-panel + nav-hint
   chrome so the dashboard itself owns the screen. Typography rides
   the screen's cqi-based tokens; the wider screen automatically grows
   every type-size in lockstep without any explicit override. */
/* Fullscreen — anchor .screen at fixed pixel positions inside a
   viewport-filling black backdrop. position:fixed bypasses every
   parent's layout (flex, padding, margin) so the 12 px black frame
   around the dashboard is guaranteed regardless of any stale or
   conflicting .wrap / .shell rule in the cascade. */
/* DEMO EMBED — index.html?demo=1 inside /demo.html's device frame.
   The iframe shows ONLY the screen: no toolbar, no info panel, no
   shell chrome — the frame graphic around it lives on demo.html.
   (Deliberately NOT .is-fullscreen: that mode hides the calendar
   pill, which is the demo's JUMP button.) */
body.demo-embed{padding:0;margin:0;background:#fff;}
body.demo-embed .wrap{padding:0;gap:0;background:none;min-height:0;justify-content:flex-start;}
body.demo-embed .nav,body.demo-embed .info-panel{display:none;}
body.demo-embed .shell{max-width:none;width:100%;padding:0;border-radius:0;box-shadow:none;background:transparent;}
body.demo-embed .screen{border-radius:0;}
html.is-fullscreen,body.is-fullscreen{background:#000 !important;margin:0 !important;}
body.is-fullscreen .wrap,body.is-fullscreen .shell{
  background:#000 !important;
  padding:0 !important;
  margin:0 !important;
  border-radius:0 !important;
  box-shadow:none !important;
}
body.is-fullscreen .screen:not(.orient-portrait){
  /* FULL-BLEED fullscreen (landscape): the dashboard fills the whole
     viewport (below the 56px nav band, inside a slim 12px black frame)
     instead of letterboxing to 4:3. To keep the typography at the SAME
     proportions as the regular page, every type token below is capped
     at its 4:3-equivalent: min(Xcqi, X*(1872/1404)cqb). On wide
     monitors the height-based cqb term wins, so text is sized exactly
     as the letterboxed 4:3 screen would size it — the extra width goes
     into roomier columns, not inflated type. On narrower viewports the
     cqi term wins and behavior matches the regular page.
     container-type:size (screen has definite fixed size here) is what
     makes cqb resolvable; the regular page stays inline-size. */
  position:fixed !important;
  inset:56px 12px 12px 12px !important;
  margin:auto !important;
  width:auto !important;
  height:auto !important;
  max-width:none !important;
  aspect-ratio:auto !important;
  border-radius:18px !important;
  container-type:size !important;
  --content-size:clamp(15px, min(1.625cqi, 2.1667cqb), 60px);
  --section-title-size:clamp(17px, min(1.875cqi, 2.5cqb), 70px);
  --hdate-size:clamp(20px, min(2cqi, 2.6667cqb), 80px);
  --edate-size:clamp(20px, min(2cqi, 2.6667cqb), 80px);
  --occasion-size:clamp(13px, min(1.5cqi, 2cqb), 50px);
  --topbar-brand-size:clamp(18px, min(4cqi, 5.3333cqb), 150px);
  --topbar-loc-size:clamp(11px, min(1.125cqi, 1.5cqb), 40px);
  --topbar-parsha-size:clamp(22px, min(4cqi, 5.3333cqb), 130px);
  /* Vertical spacing tokens are % of their parent's WIDTH, so on wide
     full-bleed viewports they'd inflate and burn the height budget
     (at 21:9 a section gap nearly doubles, squeezing Upcoming clean
     off the screen). Cap each at its 4:3-equivalent, computed against
     the 1872×1404 design grid. */
  --section-gap:min(2.2%, 1.29cqb);
  --zman-row-pad:min(0.5%, 0.15cqb);
  --shabbos-row-pad:min(0.5%, 0.15cqb);
  --learn-bar-pad:min(1.8%, 2.4cqb);
}
/* Portrait fullscreen: the stacked portrait layout depends on natural
   page flow + scrolling (fitHayomYom deliberately skips portrait), so
   a fixed-height box would clip it. Fill the width, keep natural
   height, and clear the fixed nav band — effectively the regular
   portrait page with the chrome stripped. */
body.is-fullscreen .screen.orient-portrait{
  width:100% !important;
  max-width:none !important;
  margin-top:56px !important;
  border-radius:18px !important;
}
body.is-fullscreen .info-panel{display:none;}
body.is-fullscreen .nav{position:fixed;top:0;left:0;padding:6px 12px;background:transparent;z-index:1000;}
/* Hide the battery pill in fullscreen — fullscreen is a presentation
   mode and the charge indicator doesn't belong there. Same for the
   calendar pill: no month calendar / jump picker in fullscreen, and
   with it gone the clock slides to the right edge of the bar. */
body.is-fullscreen .bat-wrap{display:none;}
body.is-fullscreen .tb-cal-btn{display:none;}
/* In fullscreen, hide every toolbar control except the exit-fullscreen
   button so the dashboard owns the chrome. .nav stays in flow (the
   .screen width math reserves a 50px nav band at the top — removing
   .nav from flow would let .screen jump up and overlap the button),
   just collapsed to its right edge. */
body.is-fullscreen .nav-toggle,
body.is-fullscreen .nav-items > *:not(#fs-btn){display:none;}
body.is-fullscreen .nav{justify-content:flex-start;}
body.is-fullscreen .nav-items{display:flex;}
/* Fullscreen backdrop is always black regardless of theme — keep the
   one visible button (exit fullscreen) AND the brand strip legible on
   it in every theme. */
body.is-fullscreen .nb{color:#f6efdd;border-color:rgba(242,236,223,0.5);}
body.is-fullscreen .nav-brand{color:#f6efdd;}
body.is-fullscreen .build-tag{color:#f6efdd;border-color:rgba(242,236,223,0.5);}
/* ================================================================
   4 · TOOLBAR BUTTONS & POPUPS
   .nb = toolbar button, .date-combo = the calendar pill,
   .dp-pop = shared popup base, .sh-pop = share, .gy-pop = year export
   ================================================================ */
.nb{background:transparent;border:1.5px solid var(--chrome-btn-line);color:var(--chrome-shell-fg);padding:0 12px;height:37px;display:inline-flex;align-items:center;justify-content:center;font-family:var(--font-body);font-size:12px;letter-spacing:0.4px;cursor:pointer;border-radius:12px;transition:background 0.15s ease,border-color 0.15s ease,color 0.15s ease;white-space:nowrap;box-sizing:border-box;}
.nb:hover:not(:disabled){background:var(--chrome-btn-hover);border-color:var(--chrome-shell-fg);}
.nb:disabled{background:transparent;border-color:var(--chrome-btn-line);color:var(--chrome-shell-fg);opacity:0.4;cursor:not-allowed;}
/* Open/focus ring: the trigger of an OPEN popup (app.js toggles .is-open) —
   neutral ink, not amber (owner preference: no yellow ring),
   the expanded hamburger, and keyboard focus. Muted: the border blends
   amber toward the neutral button line and the halo sits at 14% —
   full-strength amber + 30% glow read as a warning light in dark mode. */
.nb.is-open,.date-combo.is-open,.nav-toggle[aria-expanded="true"],.nb:focus-visible,.date-combo:focus-visible{border-color:var(--chrome-shell-fg);box-shadow:0 0 0 2px color-mix(in srgb,var(--chrome-shell-fg) 12%,transparent);outline:none;}
/* Icon buttons: explicit height so every chrome matches regardless of cascade
   path (the stand-alone .nav-toggle sits directly in .nav while the other
   icons sit in .nav-items, which previously let them pick up slightly
   different box sizes on wrapped rows). */
.nb-ico{padding:0;width:37px;min-width:37px;height:37px;line-height:1;font-size:18px;flex:0 0 auto;}
/* Icons fill ~62% of the box (20 / 34), leaving a ~6px halo on each side so
   the glyph reads clearly without touching the border. */

.date-combo{display:inline-flex;align-items:center;gap:4px;background:transparent;border:1.5px solid var(--chrome-btn-line);color:var(--chrome-shell-fg);padding:3px 8px;border-radius:12px;transition:background 0.15s ease,border-color 0.15s ease;box-sizing:border-box;}
.date-combo-ico{padding:0;width:37px;min-width:37px;height:37px;justify-content:center;cursor:pointer;}
/* The toolbar jump button duplicates the inner screen's calendar pill,
   which only disappears in the stacked portrait layout (.tb-r is
   display:none there) — so the outer button shows in portrait only. */
.shell:not(.orient-portrait) #date-pill{display:none;}
.date-combo-ico .cal-icon,.nb-ico .cal-icon{width:19px;height:19px;opacity:1;}
.date-combo:hover{background:var(--chrome-btn-hover);border-color:var(--chrome-shell-fg);}
.date-combo[role="button"]{cursor:pointer;}
.date-combo[role="button"]:focus-visible{border-color:var(--chrome-shell-fg);box-shadow:0 0 0 2px color-mix(in srgb,var(--chrome-shell-fg) 12%,transparent);outline:none;}
/* ONE-LINE TOOLBAR (tablet/mid widths): the icon buttons flex-shrink
   down to 24px — staying square via aspect-ratio, icons scaling with
   the box — so the row NEVER wraps or overflows; when the open menu
   still needs room, the brand strip yields. The <=600px phone block
   below keeps its own display:contents treatment. */
@media (min-width:601px){
  .nav{flex-wrap:nowrap;}
  .nav-items{min-width:0;}
  .nav .nb{height:clamp(26px,3.9vw,37px);}
  .nav .nb-ico,.nav .date-combo-ico{width:clamp(26px,3.9vw,37px);min-width:clamp(26px,3.9vw,37px);height:clamp(26px,3.9vw,37px);}
  .nav .nb-ico .cal-icon,.nav .date-combo-ico .cal-icon{width:52%;height:52%;}
  .nav #today-btn{padding:0 clamp(6px,1.1vw,12px);}
  .nav{gap:clamp(3px,0.7vw,8px);}
}
@media (min-width:601px) and (max-width:1023px){
  .nav:has(#nav-items:not([hidden])) .nav-brand{display:none;}
}
/* Theme button: icon follows html[data-theme-mode] set by the inline
   theme script. */
#theme-btn .theme-ico-dark,#theme-btn .theme-ico-sunset{display:none;}
html[data-theme-mode="dark"] #theme-btn .theme-ico-light{display:none;}
html[data-theme-mode="dark"] #theme-btn .theme-ico-dark{display:inline;}
html[data-theme-mode="sunset"] #theme-btn .theme-ico-light{display:none;}
html[data-theme-mode="sunset"] #theme-btn .theme-ico-sunset{display:inline;}
/* Shared popup base used by the share + download dialogs — almanac
   card stock, themed via the chrome tokens. */
.dp-pop{position:absolute;z-index:90;width:300px;background:var(--chrome-card);border:1px solid var(--chrome-hair);border-radius:12px;padding:12px 14px;box-shadow:0 12px 40px rgba(30,22,8,.35);color:var(--chrome-ink);font-family:var(--font-body);font-size:12px;display:flex;flex-direction:column;gap:8px;}
.dp-pop[hidden]{display:none;}
.dp-section-lbl{font-size:9px;letter-spacing:1px;text-transform:uppercase;color:var(--chrome-muted);margin-bottom:4px;text-align:center;}
.dp-ftr{display:flex;gap:6px;justify-content:space-between;border-top:1px solid var(--chrome-hair);padding-top:8px;}
/* .nb inside a popup card sits on card stock, not the bezel. */
.dp-pop .nb{color:var(--chrome-ink);border-color:var(--chrome-field-line);height:auto;min-height:38px;padding:8px 12px;}
.dp-pop .nb:hover:not(:disabled){border-color:var(--chrome-ink);}
.dp-ftr .nb{flex:1;}
.sh-pop{width:220px;gap:6px;}
.sh-opt{text-align:center;padding:8px 12px;}
/* Jump-to-date popup — mode tabs (Date / Hebrew / Holiday) share the
   date-picker dialog vocabulary. */
.jump-pop{width:272px;gap:8px;}
/* PHONE presentation (Joseph, 2026-07-23): in portrait the popup is a
   centered sheet over a dimmed veil instead of a popover hanging off
   the toolbar anchor. .jump-centered is set by openJump only in
   portrait; the veil shows/hides with it. */
.jump-veil{position:fixed;inset:0;z-index:89;background:rgba(32,26,14,.38);}
.jump-veil[hidden]{display:none;}
/* ── All-zmanim page (Joseph, 2026-07-23) — opened from the day
   page's Zmanim header; every catalog zman with its explanation.
   Chrome-token styled so it follows the site theme. ── */
.za-page{position:fixed;z-index:90;top:8svh;left:50%;transform:translateX(-50%);width:min(420px,calc(100vw - 24px));max-height:84svh;display:flex;flex-direction:column;background:var(--chrome-card);border:1px solid var(--chrome-hair);border-radius:14px;box-shadow:0 24px 80px rgba(0,0,0,.4);color:var(--chrome-ink);font-family:var(--font-body);}
.za-hd{padding:14px 18px 10px;border-bottom:1px solid var(--chrome-hair);flex-shrink:0;}
.za-title{font-size:10px;letter-spacing:2px;text-transform:uppercase;color:var(--chrome-muted);text-align:center;}
.za-date{font-size:14px;font-weight:700;text-align:center;margin-top:4px;}
.za-body{overflow-y:auto;padding:6px 18px 10px;min-height:0;}
.za-group{font-size:9px;letter-spacing:1.6px;text-transform:uppercase;color:var(--chrome-muted);margin:12px 0 2px;}
.za-row{padding:7px 0;border-bottom:1px dotted var(--chrome-hair);}
.za-row:last-child{border-bottom:none;}
.za-line{display:flex;justify-content:space-between;gap:10px;align-items:baseline;}
.za-l{font-weight:600;font-size:13.5px;}
.za-t{font-weight:700;font-size:13.5px;white-space:nowrap;}
.za-d{font-size:11.5px;color:var(--chrome-muted);line-height:1.35;margin-top:2px;}
.za-ftr{padding:10px 18px 14px;border-top:1px solid var(--chrome-hair);display:flex;flex-shrink:0;}
.za-close{flex:1;background:transparent;border:1px solid var(--chrome-field-line);color:var(--chrome-ink);border-radius:10px;padding:10px;font-family:var(--font-body);font-size:13px;cursor:pointer;}
.za-close:hover{border-color:var(--chrome-ink);}
/* Header affordance — website only; the capture carries no rule for
   .sec-zlink, so pinned device output is pixel-identical. */
.screen:not(.e-paper-capture) .sec-zlink{cursor:pointer;}
.screen:not(.e-paper-capture) .sec-zlink:hover{opacity:.65;}
/* Topbar parsha → Chabad.org Torah-reading link (Joseph, 2026-07-23).
   Inherits color/decoration exactly so the pinned capture is
   byte-identical; hover affordance is website-only. */
.tb-parsha-link{color:inherit;text-decoration:none;}
.screen:not(.e-paper-capture) .tb-parsha-link{cursor:pointer;}
.screen:not(.e-paper-capture) .tb-parsha-link:hover{opacity:.65;}
.jump-pop.jump-centered{position:fixed;top:16svh;left:50%;transform:translateX(-50%);margin:0;max-width:calc(100vw - 24px);box-shadow:0 24px 80px rgba(0,0,0,.4);}
/* Wider label column than the year-export popup — "HOLIDAY" / "MONTH"
   don't fit the 42px default. min-width:0 lets the selects shrink to
   the row instead of overflowing on a long option. */
.jump-pop .gy-lbl{width:56px;}
.jump-pop .gy-date{min-width:0;}
.jump-tabs{display:flex;gap:4px;}
.jump-tab{flex:1;background:var(--chrome-field);border:1px solid var(--chrome-field-line);color:var(--chrome-muted);font-family:var(--font-body);font-size:11px;letter-spacing:0.3px;padding:5px 4px;border-radius:8px;cursor:pointer;transition:background .12s,border-color .12s;}
.jump-tab:hover{background:var(--chrome-btn-hover);}
.jump-tab.is-active{background:var(--chrome-ink);color:var(--chrome-card);border-color:var(--chrome-ink);font-weight:700;}
.jump-panel{display:flex;flex-direction:column;gap:6px;}
.jump-panel[hidden]{display:none;}
.jump-err{font-size:11px;line-height:1.3;color:var(--chrome-bad);min-height:0;}
.jump-err[hidden]{display:none;}
.sh-toast{position:absolute;bottom:-32px;left:50%;transform:translateX(-50%);background:var(--chrome-ink);color:var(--chrome-card);padding:4px 12px;border-radius:4px;font-size:11px;font-weight:700;letter-spacing:0.5px;}
/* Generate-Year export popup — wider and taller than dp-pop because it lists
   every month in the range plus progress + status rows. Styled to share the
   date-picker vocabulary so the whole toolbar's dialog family reads the same. */
.gy-pop{width:340px;gap:8px;}
.gy-help{font-size:11px;line-height:1.35;color:var(--chrome-muted);font-style:normal;}
.gy-row{display:flex;align-items:center;gap:8px;}
.gy-lbl{width:42px;font-size:11px;letter-spacing:0.5px;color:var(--chrome-muted);text-transform:uppercase;}
.gy-date{flex:1;background:var(--chrome-field);border:1px solid var(--chrome-field-line);border-radius:8px;color:var(--chrome-ink);font-family:var(--font-body);font-style:normal;font-size:12px;padding:5px 8px;color-scheme:light;}
html[data-theme="dark"] .gy-date{color-scheme:dark;}
.gy-date:focus{outline:none;border-color:var(--chrome-ink);}
.gy-months{max-height:180px;overflow-y:auto;display:flex;flex-direction:column;gap:3px;border:1px solid var(--chrome-hair);border-radius:8px;padding:4px;}
.gy-months::-webkit-scrollbar{width:6px;}
.gy-months::-webkit-scrollbar-thumb{background:var(--chrome-muted);border-radius:3px;}
.gy-month-btn{display:flex;align-items:center;justify-content:space-between;gap:6px;background:var(--chrome-field);border:1px solid var(--chrome-field-line);border-radius:8px;color:var(--chrome-ink);font-family:var(--font-body);font-size:12px;letter-spacing:0.3px;padding:6px 9px;cursor:pointer;text-align:left;}
.gy-month-btn:hover:not(:disabled){background:var(--chrome-btn-hover);border-color:var(--chrome-ink);}
.gy-month-btn:disabled{opacity:0.5;cursor:default;}
.gy-month-btn.done{border-color:rgba(120,220,120,0.55);}
.gy-month-tick{font-size:11px;opacity:0.8;}
.gy-status{font-size:11px;color:var(--chrome-muted);font-style:normal;min-height:14px;line-height:1.3;}
.gy-prog{height:6px;background:var(--chrome-hair);border-radius:3px;overflow:hidden;}
.gy-prog-bar{height:100%;width:0;background:var(--chrome-ink);transition:width 0.15s linear;}
@media (max-width: 820px){
  .gy-pop{width:calc(100vw - 32px);max-width:340px;}
}

/* ================================================================
   5 · LOCATION (ZIP) OVERLAY — first visit / "Location" button
   ================================================================ */
.zip-setup{position:fixed;inset:0;background:var(--bg);display:flex;align-items:center;justify-content:center;z-index:100;padding:20px;}
.zip-box{display:flex;flex-direction:column;gap:16px;align-items:center;padding:40px 48px;background:var(--chrome-card);border:1px solid var(--chrome-hair);border-radius:var(--shell-radius);min-width:320px;max-width:90vw;box-shadow:0 28px 80px rgba(40,30,10,.35);}
.zip-title{font-family:var(--font-display);font-style:normal;font-size:36px;color:var(--chrome-ink);}
.zip-title .zt-heb{font-family:var(--font-hebrew);font-style:normal;font-weight:700;margin-left:6px;}
.zip-sub{color:var(--chrome-muted);font-size:14px;font-family:var(--font-body);font-style:normal;text-align:center;max-width:320px;}
.zip-input{background:var(--chrome-field);border:1.5px solid var(--chrome-field-line);color:var(--chrome-ink);font-size:16px;padding:12px 16px;width:280px;text-align:center;font-family:var(--font-body);border-radius:10px;}
.zip-input:focus{outline:none;border-color:var(--chrome-ink);box-shadow:0 0 0 3px color-mix(in srgb,var(--chrome-ink) 12%,transparent);}
.zip-input::placeholder{color:var(--chrome-muted);}
.zip-suggestions{width:280px;max-height:180px;overflow-y:auto;background:var(--chrome-field);border:1.5px solid var(--chrome-field-line);border-top:none;border-radius:0 0 10px 10px;margin-top:-16px;text-align:left;}
.zip-sugg{padding:8px 12px;cursor:pointer;color:var(--chrome-ink);font-family:var(--font-body);font-size:13px;border-bottom:1px solid var(--chrome-hair);}
.zip-sugg:last-child{border-bottom:none;}
.zip-sugg:hover{background:var(--chrome-btn-hover);}
.zip-or{color:var(--chrome-muted);font-family:var(--font-body);font-size:11px;font-style:normal;margin:-4px 0;}
.zip-geo{background:transparent;border:1.5px solid var(--chrome-ink);color:var(--chrome-ink);padding:12px 16px;cursor:pointer;font-family:var(--font-body);font-size:13px;font-weight:600;letter-spacing:.4px;border-radius:10px;display:flex;align-items:center;justify-content:center;gap:8px;width:280px;box-sizing:border-box;}
.zip-geo:hover{opacity:.7;}
.zip-geo:disabled{opacity:.4;cursor:wait;}
.zip-btn{background:var(--chrome-ink);border:1.5px solid var(--chrome-ink);color:var(--chrome-card);padding:12px 16px;cursor:pointer;font-family:var(--font-body);font-size:13px;font-weight:700;letter-spacing:.8px;border-radius:10px;width:280px;box-sizing:border-box;}
.zip-btn:hover{opacity:.7;}
.zip-btn:disabled{opacity:.4;cursor:wait;}
.zip-err{color:var(--chrome-bad);font-size:12px;font-family:var(--font-body);font-style:normal;min-height:16px;text-align:center;}
.zip-cancel{background:none;border:none;color:var(--chrome-muted);font-size:11px;cursor:pointer;font-family:var(--font-body);margin-top:-6px;}
.zip-cancel:hover{color:var(--chrome-ink);}

/* ================================================================
   6 · THE SCREEN — the white dashboard card
   Font sizes use cqi units, which scale with the screen's width, so
   the whole design grows and shrinks in lockstep.
   ================================================================ */
.screen{
  /* 4:3 aspect ratio of the E1003 panel (1872×1404 used landscape)
     preserved via aspect-ratio; the screen scales with its shell
     rather than being clamped to a fixed pixel grid. */
  background:var(--screen-bg);aspect-ratio:1872/1404;position:relative;overflow:hidden;border-radius:var(--screen-radius);color:var(--screen-fg);
  container-type:inline-size;
  /* Grid spacing tokens — the single source of truth for the two-col-grid
     (Zmanim / Shabbos / Fast / Upcoming). See the .two-col-grid comment. */
  --grid-col-gap:8px;
  --grid-row-gap:4px;
  --grid-cell-gap:6px;
  --grid-row-lh:1.33;
}
/* Day-switch smoothing — while .fitting is on the screen, the freshly
   built day is kept invisible so the text-fitting passes (which grow
   and shrink text until it fits) happen off-stage; the finished day
   then fades in. Layout still happens at opacity 0, so the fit
   routines measure normally. The calendar overlay is excluded so an
   open calendar never blinks. */
.screen:not(.fitting) > *{transition:opacity .18s ease;}
.screen.fitting > *:not(.yc-overlay){opacity:0;}
/* During a PNG capture the content must be fully opaque with no
   transition — a capture that lands mid-fade would come out gray. */
.screen.e-paper-capture > *,.screen.capture-active > *{transition:none !important;opacity:1 !important;}
/* Capture pinning — pin .screen at the panel's native 1872 CSS px so
   html2canvas runs at scale=1 and produces a 1872×1404 canvas without
   any subsequent rescale. Pinned off-screen so the live page doesn't
   visibly reflow. */
.screen.e-paper-capture{
  position:fixed !important;
  left:-10000px !important;
  top:0 !important;
  width:1872px !important;
  height:auto !important;
  max-width:none !important;
  aspect-ratio:1872/1404 !important;
  border-radius:0 !important;
}
/* Applied for the duration of html2canvas capture. Forces grayscale
   antialiasing so the glyph edges become clean single-channel gradients
   — the 16-level quantizer then maps them cleanly to the even-spaced
   target levels instead of the orphan colored pixels that subpixel RGB
   bleed leaves floating above letters and inside the counters of
   'g' / 'a' / 'o'. */
.screen.capture-active,.screen.capture-active *{
  -webkit-font-smoothing:antialiased !important;
  -moz-osx-font-smoothing:grayscale !important;
  font-smooth:never !important;
}

/* ================================================================
   7 · TOP BAR — location stack left, parsha centered, battery right
   ================================================================ */
/* Floating gray bar inset from the screen edges. Side insets (0.9%)
   equal the top inset (1.2%) in real pixels on the 4:3 panel. */
.tb{position:absolute;top:0;left:var(--left-padding);right:var(--right-padding);height:calc(var(--topbar-height) + 2.4%);background:transparent;display:flex;align-items:center;justify-content:space-between;padding:0 8px;gap:2%;z-index:10;border-radius:0;color:#000;}
/* Dotted almanac rule under the topbar — drawn as an overlay (not a
   border) so the bar's content box, and with it the vertical pill
   centering, is identical to the calendar/jump headers. Spans the .tb
   box, whose insets now equal the learn-bar's, so the top and bottom
   rules are exactly the same width. */
.tb::after{content:"";position:absolute;left:0;right:0;bottom:0;height:var(--sep-weight);background-image:var(--sep-dots-h);background-size:var(--sep-period) var(--sep-weight);background-repeat:repeat-x;}
/* Edge screens (§15 __bayitRenderEdge) reuse the real .tb container for
   their JUMP pill so it sits at exactly the day-page position (same
   insets, same capture pixel-snapping). The bar itself stays chromeless
   — no dotted topbar rule (the boundary card draws its own centered
   rules) — and rises above the edge overlay (z-index 40). */
.tb.tb-edge{z-index:50;}
.tb.tb-edge::after{content:none;}
.tb-l{display:flex;align-items:center;gap:calc((var(--left-padding) + 8px) * 2);flex:0 0 auto;min-width:0;}
/* .tb-c is absolutely centered on the topbar so the parsha sits at the
   actual page center — keeping it in the flex flow let the Chabad /
   location column on the left and the battery pill on the right push
   it off-center. .tb itself gets justify-content:space-between so the
   left and right columns still anchor to the edges. */
/* Clip ONLY horizontally so long parshiot still can't spill into the
   Chabad/location column or the battery pill — but overflow-y:visible
   lets the parsha's -webkit-text-stroke:4px paint above/below the
   line-box without being clipped. The old overflow:hidden + padding
   fudge was cutting glyph tops (ל / ק / ה) in html2canvas downloads
   because html2canvas computes the clip rect tight against the
   border-box. overflow-x:clip + overflow-y:visible is supported by
   both live browsers and html2canvas v1. */
.tb-c{display:flex;align-items:center;gap:6px;min-width:0;overflow-x:clip;overflow-y:visible;justify-content:center;position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);max-width:52%;}
/* Clock↔calendar gap matches the battery↔location gap on .tb-l so the two
   inner gaps read symmetric across the bar. */
.tb-r{display:flex;align-items:center;gap:calc((var(--left-padding) + 8px) * 2);flex:0 0 auto;min-width:0;justify-content:flex-end;}
/* Battery indicator — thunderbolt + percentage */
/* Battery info sits in its own white pill on the right side of the
   topbar. Override the topbar's -webkit-text-stroke so the pct number
   reads as plain black on white (no outline inside the pill). */
/* One shared pill size: battery, TODAY, and calendar button all render
   at exactly 6.6cqi × 3cqi so the chrome reads symmetrically. */
.bat-wrap{display:inline-flex;align-items:center;justify-content:center;gap:3px;flex-shrink:0;background:#fff;border:1.5px solid #000;box-shadow:0 1px 2px rgba(0,0,0,0.08);border-radius:100px;height:3cqi;width:6.6cqi;padding:0;box-sizing:border-box;-webkit-text-stroke:0;}
/* Browsers with no Battery Status API (Safari/WebKit — app.js sets
   html.no-battery) hide the pill everywhere in the live view instead
   of showing an empty shell; captures force it back below so
   downloaded PNGs keep the canonical e-paper layout. */
html.no-battery .bat-wrap{display:none;}
html.no-battery .screen.e-paper-capture .bat-wrap{display:inline-flex;}
.bat-wrap svg{position:relative;top:1px;left:-1px;}
.bat-pct{font-family:var(--font-body);font-size:var(--topbar-loc-size);color:#000;-webkit-text-stroke:0;}
/* Top bar elements */
.tb-brand{font-family:var(--font-display);font-style:normal;font-size:var(--topbar-brand-size);color:var(--topbar-fg);white-space:nowrap;}
.tb-brand-heb{font-family:var(--font-hebrew);font-size:var(--topbar-brand-size);color:var(--topbar-fg);font-weight:600;white-space:nowrap;}
.tb-sep{color:var(--topbar-fg);font-family:var(--font-body);font-size:var(--topbar-loc-size);white-space:nowrap;}
.tb-brand-dot{color:var(--topbar-fg);font-family:var(--font-body);font-size:calc(var(--topbar-loc-size) * 2);line-height:1;white-space:nowrap;}
.tb-loc{font-family:var(--font-body);font-style:normal;font-size:calc(var(--topbar-parsha-size) * 0.32);color:var(--topbar-fg);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}
.tb-nusach{font-family:var(--font-body);font-style:normal;font-size:calc(var(--topbar-parsha-size) * 0.32);color:var(--topbar-fg);white-space:nowrap;}
.tb-stack{display:flex;flex-direction:column;align-items:flex-start;gap:1px;line-height:1.1;align-self:center;}
.tb-stack .tb-nusach,.tb-stack .tb-loc{overflow:visible;}
/* line-height:1.35 explicit — Noto Serif Hebrew ships with ascenders
   that extend well above the em-box at weight 700+, and html2canvas
   measures the line-box tightly for capture. Without the extra
   headroom the top of ק / ל / ה clipped at the topbar's upper edge in
   the downloaded PNG even though the browser rendered them fine. */
.tb-parsha-heb{font-family:var(--font-hebrew);font-size:var(--topbar-parsha-size);font-weight:700;color:var(--topbar-fg);direction:rtl;white-space:nowrap;line-height:1.35;}
.tb-parsha-eng{font-family:var(--font-body);font-style:normal;font-size:var(--topbar-loc-size);color:var(--topbar-fg);white-space:nowrap;}
.tb-parsha-dot{color:var(--topbar-fg);font-family:var(--font-body);font-size:calc(var(--topbar-loc-size) * 2);line-height:1;white-space:nowrap;}
.tb-bh{font-family:var(--font-hebrew);font-size:var(--topbar-brand-size);color:var(--topbar-fg);font-weight:600;}
/* Calendar button — pill-shaped like the battery pill on the left so
   the topbar reads symmetrically. */
/* flex-shrink:0 — same as .bat-wrap. Without it the button silently
   shrinks below its 6.6cqi spec: .tb-r's percentage-based gap resolves
   to 0 during intrinsic sizing and to ~10px more at final layout, and
   flex hands that deficit to the only shrinkable child (this button,
   whose min-content is just the small svg). The battery pill kept its
   full width (it pins flex-shrink:0), so the two "identical" pills
   rendered ~10px apart in width on web AND in the PNG. */
.tb-cal-btn{background:#fff;border:1.5px solid #000;color:#000;cursor:pointer;padding:0;width:6.6cqi;height:3cqi;box-sizing:border-box;display:inline-flex;align-items:center;justify-content:center;border-radius:100px;-webkit-text-stroke:0;box-shadow:0 1px 2px rgba(0,0,0,0.08);transition:background .1s,border-color .1s;flex-shrink:0;}
.tb-cal-btn:hover{background:#f0f0f0;border-color:#000;}
/* Edge screens' JUMP pill (§15 __bayitRenderEdge): the day-page
   calendar pill's exact box and border, wearing the word JUMP instead
   of the icon (Joseph's mockup). */
.tb-jump-btn{font-family:var(--font-body);font-weight:700;font-size:calc(var(--topbar-loc-size) * 1.25);letter-spacing:0.06em;color:#000;}
.tb-cal-btn svg{width:calc(var(--topbar-loc-size) * 1.3);height:calc(var(--topbar-loc-size) * 1.3);}

/* ================================================================
   8 · LEFT COLUMN (and shared body layout)
   ================================================================ */
/* Body fills the screen below the top bar; bottom padding reserves
   room for the learning bar pinned along the bottom. */
.body{position:absolute;top:calc(var(--topbar-height) + 2.4%);left:0;right:0;bottom:0;display:flex;flex-direction:column;padding-bottom:7%;}
.body-main{display:flex;flex:1;min-height:0;}
/* Vertical divider between the L and R panels. Color/width are pinned
   to the same tokens the horizontal rules use so all bars on the screen
   read as the same line treatment. Top/bottom margins are near-equal so
   the divider sits visually centered between the topbar and the learn-bar
   (measured: ~equal gaps at both 1872×1404 and live wide widths). Bottom
   is a hair larger than top to offset the learn-bar's reserved band; it
   still leaves ~115 px clearance at native, so a dense day's taller
   learn-bar can't collide with the divider's bottom edge. */
/* Dotted, not solid — matches the zmanim ledger baselines and the
   learn-bar rules so every separator on the screen reads as one
   consistent treatment. Painted with the shared --sep-dots-v
   definition (see :root) so its dot rhythm is pixel-identical to the
   horizontal rules'. The width swap (border-left on a width:0 box →
   a --sep-weight-wide background) is layout-neutral. */
.vdiv{width:var(--sep-weight);background-image:var(--sep-dots-v);background-size:var(--sep-weight) var(--sep-period);background-repeat:repeat-y;margin:5.25% 0 5.75%;flex-shrink:0;}

/* L panel — clock pinned at the top with a fixed reserved height so
   the firmware's live-clock overlay rectangle is stable day-to-day.
   Everything else lives in .L-content, which fills the remaining
   height and vertically centers its children as a single block. The
   date stack + sections shift up or down with content length but the
   clock stays in the same pixel rectangle every day. */
.L{width:var(--left-panel-width);padding:1.4% var(--left-padding) 1.2% var(--left-padding);display:flex;flex-direction:column;justify-content:flex-start;overflow:hidden;align-items:stretch;}
/* Clock — lives in the topbar's right group (before the calendar
   pill), sized relative to the parsha so the bar reads as one unit.
   The .firmware-overlay class hides the rendered digits during PNG
   capture (visibility:hidden preserves the box); the device firmware
   paints the live clock onto this rectangle, anchored to its RIGHT
   edge (the group is right-aligned so that edge is stable while the
   time string's width varies). */
.tb-clock{display:inline-flex;align-items:baseline;justify-content:flex-end;gap:0.35cqi;white-space:nowrap;}
.ct{font-family:var(--font-display);font-size:calc(var(--topbar-parsha-size) * 0.96);line-height:.9;letter-spacing:-1px;font-weight:400;}
.ap{font-family:var(--font-body);font-style:normal;font-weight:700;font-size:calc(var(--topbar-parsha-size) * 0.42);}
/* Centered content block — fills the remaining vertical space below
   the clock and above the learn-bar; flex:1 grabs all leftover height,
   justify-content:center packs the children to the vertical middle.
   The first children (date / occasion / daily-notes) flow naturally
   above the sections — no fixed slots, no reserved gaps. */
.L-content{flex:1;min-height:0;display:flex;flex-direction:column;justify-content:safe center;align-items:stretch;gap:0;overflow:hidden;}
/* Prevent the flex layout from compressing individual L-content
   children to 0 when total natural height exceeds the column. Some
   children (.date-line) have overflow:hidden which signals to flex
   layout that they may shrink. Without flex-shrink:0 the date line
   collapses to height:0 and the first thing the user notices in
   fullscreen is the missing date. */
.L-content > *{flex-shrink:0;}
/* Date line: <English date> · <Hebrew date> on one centered row. The
   parent .date-line carries the base font-size; children inherit so a
   single inline-style shrink on .date-line scales every piece in
   lockstep. Hebrew gets a small bump (1.1em) because Noto Serif Hebrew
   has a smaller x-height than Noto Serif at the same font-size. */
.date-line{display:flex;flex-direction:row;align-items:baseline;justify-content:center;gap:.45em;width:100%;white-space:nowrap;overflow:hidden;font-size:var(--edate-size);line-height:1.25;}
.edate{font-family:var(--font-body);font-style:normal;font-size:1em;line-height:1.25;white-space:nowrap;}
.hdate{font-family:var(--font-hebrew);font-size:1.1em;font-weight:700;direction:rtl;line-height:1.25;white-space:nowrap;}
.date-sep{font-family:var(--font-body);font-style:normal;font-size:1em;line-height:1.25;opacity:.7;}
/* Occasion line — sits under the date line, centered. Sized at
   --occasion-size which is capped <= --edate-size so it never reads
   bigger than the date. */
.occasion{font-family:var(--font-body);font-style:normal;font-size:var(--content-size);color:var(--screen-fg);line-height:1.3;display:flex;flex-wrap:wrap;column-gap:.45em;row-gap:.05em;justify-content:center;text-align:center;white-space:nowrap;}
.occ-item{white-space:nowrap;}
.occ-item:not(:first-child)::before{content:"· ";margin-right:.15em;}
/* A long occasion list flow-wraps between items (flex-wrap above) —
   the one-item-per-line .stacked column was removed (Joseph,
   2026-07-24: "combine into lines"). */
.rule{border:none;border-top:var(--rule-weight) solid var(--rule-color);margin:var(--section-gap) 0 .8%;}
/* Section label — body font, uppercase, lightly tracked */
.sec,.hy-lbl{font-family:var(--font-body);font-size:var(--section-title-size);letter-spacing:1px;font-weight:700;text-transform:uppercase;}
/* row-gap keeps the supplementary .sec-pa label (Pirkei Avos on
   the Shabbos header, Ushpizin on the Zmanim header) tight under
   the main title when the row wraps on narrow phones — mirrors the
   1 px gap between "Chabad" and the city line in the topbar stack,
   so a wrapped header reads as a two-line unit rather than two
   loose rows. */
.sec{margin-bottom:var(--label-gap);flex-shrink:0;display:flex;justify-content:space-between;align-items:baseline;column-gap:10px;flex-wrap:nowrap;white-space:nowrap;overflow:hidden;}
.sec > *,.sec .sh-link,.sec .sec-pa{white-space:nowrap;}
/* fitSections drops the supplement (Pirkei Avos / Molad) onto its own line
   under the section title when keeping it inline would force a >15% shrink.
   Title keeps full size; the supplement reads as a second-row caption. */
.sec.sec-wrap{flex-wrap:wrap;row-gap:.1cqi;}
.sec.sec-wrap > *{flex-basis:100%;}
.sec.sec-wrap .sec-pa,.sec.sec-wrap .molad-pa{text-align:left;}
/* Inline Pirkei Avos link that sits on the right side of the Shabbos
   section header: same font, friendlier (non-uppercase, lighter) so it
   reads as a supplement to the section title rather than a second title. */
/* Supplementary section-header label (Pirkei Avos, Ushpizin).
   .8em renders against the surrounding .sec font size, giving a
   natural typographic step down from the section title. */
.sec-pa{font-size:calc(var(--content-size) * 0.75);letter-spacing:0;text-transform:none;font-weight:600;color:inherit;text-decoration:none;white-space:nowrap;}
/* Halachic action reminders (pre-existing flame / Eruv Tavshilin) —
   marker class only, no styling of its own: the note inherits the
   surrounding .sec-pa supplement style, so it renders at exactly the
   same size/weight as the other small annotations (the Molad line,
   Birkas Ha'Ilanos / Tashlich notes). Joseph's ruling — an earlier
   1.2em enlargement was reverted. */
.sec-flame{}
.sec-pa:hover{opacity:.7;}
/* Link nested inside a .sec-pa container (Pirkei Avos when it shares
   the slot with another supplement) — inherit the container's look. */
.sec-pa-link{color:inherit;text-decoration:none;}
.sec-pa-link:hover{opacity:.7;}
/* Shabbos section-header link: inherits color, size, weight, uppercase
   letter-spacing from the surrounding .sec; no underline so it reads
   visually as a plain header (the user didn't want the dotted line).
   A subtle opacity nudge on hover keeps the tap affordance for
   pointer-enabled browsers. */
.sh-link{color:inherit;text-decoration:none;cursor:pointer;}
.sh-link:hover{opacity:.85;}
.zrow,.shrow,.up-row{display:flex;justify-content:space-between;align-items:center;width:100%;padding:var(--zman-row-pad) 0;}
/* Two-column grid — shared by Zmanim, Shabbos, Fast and Upcoming.
   ALL of its spacing flows through four tokens, so each context tunes
   spacing in ONE place (search "--grid-" for every assignment):
     --grid-col-gap   gap between the two label+time pairs
     --grid-row-gap   vertical gap between rows
     --grid-cell-gap  gap between a label and its time
     --grid-row-lh    row line-height (dominates perceived spacing)
   Defaults live on .screen: col 8px / row 4px / cell 6px / lh 1.33. */
.two-col-grid{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);column-gap:var(--grid-col-gap,8px);row-gap:var(--grid-row-gap,4px);width:100%;}
.two-col-grid > *{column-gap:var(--grid-cell-gap,6px);min-width:0;}
.two-col-grid .zl,.two-col-grid .zt,
.two-col-grid .shl,.two-col-grid .sht,
.two-col-grid .up-l,.two-col-grid .up-d{line-height:var(--grid-row-lh,1.33);}
/* Body-text rows (Zmanim, Shabbos, Upcoming) sit slightly below the
   .R panel's body size so the L column can hold a long label + a
   12-char time without spilling. Anchored to --content-size so the
   ratio is preserved as the screen scales. */
.two-col-grid .zl,.two-col-grid .zt,
.two-col-grid .shl,.two-col-grid .sht,
.two-col-grid .up-l,.two-col-grid .up-d{font-size:var(--content-size);}
/* Grid-spacing token assignments per context. cqi values scale with the
   screen width (at ~932px live, .87cqi ≈ 8px — same as the fixed default;
   at native 1872 capture it's ≈ 16px). Wide landscape and the PNG capture
   share one pair of values so device output matches the live wide view.
   NOTE: container-query rules cannot match .screen itself (it IS the
   container), so context assignments are made on .two-col-grid; an
   element-own custom property also always beats one inherited from
   .screen, which keeps the precedence chain flat and predictable. */
@container (min-width: 701px){
  .screen:not(.orient-portrait) .two-col-grid{--grid-col-gap:.87cqi;--grid-row-gap:.23cqi;}
}
.screen.e-paper-capture .two-col-grid{--grid-col-gap:.87cqi;--grid-row-gap:.23cqi;}
/* Fullscreen: 25% more horizontal gap (0.87 × 1.25 ≈ 1.09) so the wider
   panel doesn't feel cramped under the 0.75 font-scale override. The
   body.is-fullscreen prefix out-specifies the container-query rule above,
   so no !important is needed. */
body.is-fullscreen .screen:not(.orient-portrait) .two-col-grid{--grid-col-gap:min(1.09cqi,1.4533cqb);--grid-row-gap:min(.29cqi,.3867cqb);}
/* Values (time like "10:51 AM", date like "Sun, May 17") must stay on
   one line — splitting "10:51" from "AM" looks broken. Labels also
   stay nowrap on the wide E1003 column: clipping triggers
   fitTwoColRows' anyClipped() check and the shrink loop finds a
   font-size that fits, which reads cleaner than two-line labels. */
.two-col-grid .zt,.two-col-grid .sht,.two-col-grid .up-d{white-space:nowrap;}
/* overflow:hidden clips long labels horizontally; --grid-row-lh (≥1.3)
   keeps the "g"/"p"/"y" descender tails inside the clip region in the
   downloaded PNG (html2canvas rasterizes text 1-2px lower than the
   browser, so tails fell outside a 1.2 line-height box). */
/* Labels stay on ONE LINE always; fitTwoColRows shrinks them when
   the label is too long for the cell. nowrap is intentional —
   wrapping to a second line takes the row out of the body band and
   breaks vertical rhythm. !important here is a defensive belt against
   any future rule (or stale-cached older rule) trying to set normal. */
.two-col-grid .zl,.two-col-grid .shl,.two-col-grid .up-l{min-width:0;overflow:hidden;white-space:nowrap !important;padding-right:3px;
  /* padding-right shrinks the effective content area by 3px, so
     fitTwoColRows' scrollWidth>clientWidth check kicks in slightly
     earlier than text-flush-against-the-edge. That gives the
     rightmost glyph (the "s" of "Latest Shacharis", etc.) 3px of
     clear room from the cell boundary. */}
.two-col-grid .zt,.two-col-grid .sht,.two-col-grid .up-d{flex-shrink:0;}
/* fitTwoColRows lets the label wrap onto a second line within its own cell
   when keeping it on one line would force a >15% shrink across the grid.
   The cell width stays the same (the row doesn't promote to full-width),
   so the layout's column pairing is preserved; only the offending row
   grows taller. line-height tightens so the wrapped label sits as a
   single visual block beside its value. */
.two-col-grid .row-wrap .zl,
.two-col-grid .row-wrap .shl,
.two-col-grid .row-wrap .up-l{
  white-space:normal !important;
  overflow:visible;
  line-height:1.2;
}
/* Two-segment labels (merged "Shab' Ends / X Candles"): inline-block
   segments break BETWEEN each other before wrapping inside one — the
   seam after "/" is the preferred wrap point (Joseph, 2026-07-23) —
   and max-width lets an over-long segment still wrap internally
   instead of ever forcing a grid shrink. */
.shl-seg{display:inline-block;max-width:100%;}
/* Personal Upcoming labels: name segment + kind segment (Joseph,
   2026-07-23 — "Yaya K.'s" stays whole; the break prefers the seam
   before "Bday"/"Yahrzeit"). Same inline-block mechanics as .shl-seg. */
.up-seg{display:inline-block;max-width:100%;}
/* Shabbos rows ALWAYS keep their column pairing (Joseph, 2026-07-24)
   — the full-width/.sh-single and stacked-cell experiments are gone.
   Long titles wrap inside their cell; .sh-wdstack above narrows the
   value only after the title has already wrapped. */
/* Body-row labels: Medium 500 keeps the label readable next to the
   Bold 700 value in the right column without competing visually for
   the same weight level. line-height:1.4 keeps serif descenders
   (g, p, y in "Plag HaMincha", "Lag BaOmer", "Candle Lighting")
   inside the element's clip region; html2canvas rasterizes text one
   or two pixels lower than the native browser, so the descender tails
   used to fall outside a 1.2-line-height box in the PNG capture. */
.zl,.shl,.up-l{font-family:var(--font-body);font-size:var(--content-size);font-weight:400;color:var(--screen-fg);line-height:1.4;}
/* Hebrew-only Upcoming labels (Chabad Yomei d'Pagra: י״ט כסלו, ג׳
   תמוז, etc.) — switch to the Hebrew font family used by the Omer
   block so the Hebrew glyphs render with consistent proportions and
   access the Noto Serif Hebrew variable-font weight axis. Weight 900
   gives these focal Hebrew labels visual parity with the surrounding
   English labels in the cell. */
.up-l-heb{font-family:var(--font-hebrew);font-weight:900;font-variation-settings:"wght" 900;}
.up-link{text-decoration:none;color:inherit;cursor:pointer;}
.up-link:hover{opacity:.65;}
.zt,.sht,.up-d{font-family:var(--font-body);font-size:var(--content-size);font-weight:700;color:var(--screen-fg);white-space:nowrap;margin-left:4px;line-height:1.4;}
/* Merged personal rows ("May 24 (E) + Jun 19 (H)") may wrap — the
   breakable space sits only before the "+", NBSPs glue each date. */
.up-d.up-d-merged{white-space:normal;text-align:right;}
.two-col-grid .up-d.up-d-merged{white-space:normal;}
/* When the ROW is under width pressure (fitUpcoming set .row-wrap
   because the label clipped), squeeze the merged date to its widest
   chunk so it takes two lines at the "+" break and the label gets the
   freed width for two lines - 2+2 instead of 3+1. */
.two-col-grid .row-wrap .up-d.up-d-merged{width:min-content;}
/* Dual-date weekday prefixes (Joseph, 2026-07-22): each merged chunk
   (.up-dl) carries a hidden weekday span (.up-dwd). fitUpDualWd turns
   them on (.up-d-wd-on) ONLY when the cell already occupies two
   lines, so the lines read "Sat, Jul 25 (H)" / "Wed, Aug 5 (E)" like
   the single-date rows — and a one-line entry never gains a second
   line just for the weekday. nowrap on the chunk keeps each line
   unbreakable (same job as its internal NBSPs, weekday included). */
.up-d-merged .up-dl{white-space:nowrap;}
.up-d-merged .up-dwd{display:none;}
.up-d-merged.up-d-wd-on .up-dwd{display:inline;}
/* THREE-LINE CAP (Joseph, 2026-07-23): a label may take at most two
   lines. fitTwoColRows sets .up-wd-off on a row whose wrapped label
   still measures three — the weekday prefixes come off the date lines
   (merged .up-dwd AND single-date .up-swd) so the narrower date cell
   returns width to the label. !important beats .up-d-wd-on. */
.up-row.up-wd-off .up-dwd{display:none !important;}
.up-row.up-wd-off .up-swd{display:none;}
/* Season boundary lines in calendar cells (Three Weeks / Nine Days
   begin-end) - present but quieter than holiday titles. */
.yc-season{font-style:italic;font-weight:400;color:var(--screen-fg);opacity:.75;}
/* Weekday tag inside a Shabbos-section time. Stacked ON ITS OWN LINE
   above the time (right-aligned to match) rather than inline, so the
   time cell stays narrow — that leaves the label enough width to wrap
   to two lines instead of three, keeping both halves of the row the
   same height. Lighter than the bold time so the clock still leads.
   Only rendered on multi-day Shabbos/Yom Tov periods. */
/* Weekday tag: INLINE with the time by default (Joseph, 2026-07-24:
   "Sat 7:12 pm" stays whole — the TITLE wraps first). fitTwoColRows
   stacks it (.sh-wdstack) only when the wrapped title still can't
   fit beside the intact value. */
.shwd{display:inline;text-align:unset;margin-inline-end:0.35em;font-weight:700;white-space:nowrap;line-height:inherit;}
.shtime{white-space:nowrap;}
/* WRAPPED Shabbos row (Joseph, 2026-07-24 final): both halves split
   across the SAME two lines — the title wraps in its cell (the
   inline-block .shl-seg seam is the preferred break) and the
   day+time stack right-aligned beside it, day over time:
     Shab' Ends /      Sat
     Sukkos Candles    7:21 pm
   The narrow stacked value ("Sat" / "7:21 pm") leaves the label most
   of the cell width, so the row is exactly two aligned ledger lines.
   Only .shrow rows do this; zmanim/upcoming keep their cells. */
.two-col-grid .shrow.row-wrap .sht{display:flex;flex-direction:column;align-items:flex-end;line-height:1.2;}
.two-col-grid .shrow.row-wrap .shwd{display:block;margin-inline-end:0;text-align:right;line-height:inherit;}
.two-col-grid .shrow.row-wrap .shtime{white-space:nowrap;}
/* FALLBACK (.sh-flow, set by fitTwoColRows) for the rare label that
   would need a THIRD line beside the stacked value ("Shab' Ends /
   Simchas Torah Candles"): the title flows at FULL cell width and
   the day+time park inline at the right edge of its last line —
     Shab' Ends / Simchas Torah
     Candles         Sat 7:11 pm
   — two lines either way, never three. */
.two-col-grid .shrow.row-wrap.sh-flow{display:block;position:relative;}
.two-col-grid .shrow.row-wrap.sh-flow .shl{display:block;padding-right:0;}
.two-col-grid .shrow.row-wrap.sh-flow .shl-seg{display:inline;}
.two-col-grid .shrow.row-wrap.sh-flow .sht{display:block;position:absolute;right:0;bottom:var(--zman-row-pad,0);margin-left:0;}
.two-col-grid .shrow.row-wrap.sh-flow .shwd{display:inline;margin-inline-end:0.35em;text-align:unset;}

/* ================================================================
   9 · RIGHT COLUMN — HaYom Yom paragraph and the Omer block
   ================================================================ */
.R{width:calc(100% - var(--left-panel-width));padding:1.4% var(--right-padding) 1.2% var(--right-padding);display:flex;flex-direction:column;justify-content:safe center;overflow:hidden;text-align:left;}
.hy-lbl{margin-bottom:var(--label-gap);flex-shrink:0;}
/* HaYom-Yom cross-column flow (landscape long days) — see
   fitHayomYomFlow(). The entry starts in this L block (its HEAD, below
   the Omer) and continues in R. Both columns keep their default vertical
   centering (no flex-start override) so a short day sits centered, not
   pinned to the top. Block (not flex) so scrollHeight reflects the true
   content height the fill search measures against. margin-top mirrors a
   full section break (rule top + bottom margin) so the gap above
   HaYom-Yom equals the Zmanim→Shabbos→Upcoming gaps; .hy-l and .rule are
   both direct children of .L-content so the calc resolves identically. */
.hy-l{display:block;flex-shrink:0;overflow:hidden;margin-top:calc(var(--section-gap) * 1.1 + 0.8%);}
.hy-l .hy-text-l{overflow:visible;}
/* HaYom-Yom paragraph: anchored to --content-size so the body text
   in the R panel matches the body band the L panel uses. Medium 500
   keeps the paragraph readable as body weight without competing with
   the bold section title above. */
.hy-text{font-family:var(--font-body);font-size:var(--content-size);font-weight:400;line-height:var(--content-line-height);text-align:left;overflow:hidden;flex-shrink:1;min-height:0;}
/* HaYom-Yom part label ("Adar I" / "Adar II" etc.): heavier weight so
   the section break reads distinctly from the body. The gap ABOVE a part
   (before "Adar II") is a full section break so the two halves of a
   leap-year entry separate like the L-column sections; the gap BELOW the
   label (to its paragraph) is the shared --label-gap, so it matches the
   HaYom-Yom title→Adar I distance for both Adar I and Adar II. */
.hy-part-lbl{font-style:normal;font-weight:700;margin-top:0.8em;margin-bottom:var(--label-gap);}
.hy-part-lbl:first-child{margin-top:0;}
.hy-part-text{margin-top:0;}
/* Daily halachic notes — small lines under the date stack that surface
   only when a non-default rule applies (no tachanun, hallel said today,
   seasonal-insertion transition). Each line is its own block so the
   layout stays clean when only one fires. */
/* Halachic info lines — under the occasion line, centered. Cap their
   size at the occasion / edate tier so they never read larger than
   the date above them. */
.daily-notes{display:flex;flex-direction:column;gap:.15em;margin:.2% 0 .2%;flex-shrink:0;align-items:center;text-align:center;}
.insertion-line{font-family:var(--font-body);font-size:var(--content-size);font-weight:400;color:var(--screen-fg);line-height:1.3;text-align:center;}
/* Note lines carry ·-separated cues. They wrap BETWEEN cues (never mid-
   cue) like .occasion, so a long day (e.g. the Aseres Yemei Teshuvah
   davening additions) flows onto a second centered line instead of
   overflowing .L-content's hidden overflow and clipping on both edges. */
.note-line{font-family:var(--font-body);font-size:var(--content-size);font-weight:500;color:var(--screen-fg);line-height:1.3;display:flex;flex-wrap:wrap;justify-content:center;column-gap:.45em;row-gap:.05em;}
.note-item{white-space:nowrap;}
.note-item:not(:first-child)::before{content:"· ";margin-right:.15em;}
/* .sol = start-of-line: an item that wrapped to a new row. fitNoteSeparators
   tags it so its leading "·" is dropped — dots sit only BETWEEN items that
   share a line, never dangling at a line start. */
.note-item.sol::before{content:none;}
.occ-item.sol::before{content:none;}
/* Molad annotation — sits next to the "Zmanim" section title on
   Shabbos Mevarchim as a .sec-pa (right-aligned, smaller, lighter).
   .molad-pa is just a marker class so fitSections can shrink it in
   lockstep with the title if the combined row overflows. No
   additional styling — reads as plain .sec-pa, matching the
   Pirkei Avos chapter label that sits next to the SHABBOS title. */
/* Highlighted zmanim row ("Stay up until", Erev Shavuot) — reads at the
   SAME weight as every other zmanim row (label + value), no extra bold. */
/* Omer block — header row (English day count + Hebrew sefirot on the
   same line) followed by three Hebrew lines: bracha, count (bold,
   focal), HaRachaman. No labels, no per-line wrap. Each Hebrew line is
   sized to fit on one line by fitOmerLines, with bracha + HaRachaman
   sharing one size and the count line sized independently (so its
   bold weight reads as the focal value). */
/* The top rule sits at the TOP of the HaYom-Yom → Omer gap (a small
   margin above the border, the rest of the gap as padding below it) so
   the line reads as closing the HaYom-Yom entry rather than capping
   the Omer block. The margin/padding swap keeps the total gap between
   HaYom-Yom and the Omer unchanged. */
.omer-block{padding:calc(var(--section-gap) * 1.1 + 0.8%) 0 .4%;border-top:var(--rule-weight) solid var(--rule-color);margin-top:.8%;flex-shrink:0;display:flex;flex-direction:column;gap:calc(var(--label-gap) * 0.6);}
/* Title -> first Hebrew line gap matches a section label -> content gap
   (like ZMANIM -> its rows). The block's flex `gap` handles the tighter
   line-to-line spacing; this margin-bottom tops it up to a full
   --label-gap so only the header sits a touch further from the body. */
.omer-header{display:flex;flex-direction:row;align-items:baseline;justify-content:space-between;column-gap:1cqi;width:100%;white-space:nowrap;overflow:hidden;flex-shrink:0;font-size:var(--section-title-size);margin-bottom:calc(var(--label-gap) * 0.25);}
.omer-title{font-family:var(--font-body);font-size:1em;letter-spacing:1px;font-weight:700;text-transform:uppercase;white-space:nowrap;}
.omer-sefira{font-family:var(--font-hebrew);font-size:var(--content-size);font-weight:700;direction:rtl;white-space:nowrap;}
/* Three Hebrew omer rows — bracha (top), count (middle, focal), and
   HaRachaman (bottom). All at the body Hebrew size by default; the
   count line is overridden below to render slightly larger so it
   reads as the day's focal value. overflow:hidden is intentionally
   omitted here so fitOmerLines can measure scrollWidth correctly
   when the text doesn't fit on one line; the parent .R panel clips
   any visual overflow. */
.omer-heb,.omer-count-line,.omer-harachaman{font-family:var(--font-hebrew);direction:rtl;line-height:1.6;text-align:right;width:100%;white-space:nowrap;font-size:var(--content-size);font-weight:500;}
/* Day-count middle line: the FOCAL line of the omer block — the main
   thing being counted. It carries the heaviest weight (Black 900 + a
   0.4px paint-stroke, same treatment the bracha/HaRachaman used to get)
   while those siblings drop to the normal body weight, so the count
   reads as the one bold line and the surrounding text stays quiet. */
.omer-count-line{font-weight:700;font-variation-settings:"wght" 700;font-size:var(--content-size);}


/* ================================================================
   10 · LEARNING BAR — the Chumash…Daf Yomi strip along the bottom
   ================================================================ */
.learn-bar{position:absolute;bottom:0;left:var(--left-padding);right:var(--right-padding);border-top:var(--rule-weight) solid var(--rule-color);padding:var(--learn-bar-pad) 0 calc(var(--learn-bar-pad) * 3 / 4);display:flex;align-items:stretch;justify-content:space-between;overflow:hidden;flex-wrap:nowrap;}

/* Each item is a stacked card: small uppercase label on top, larger bold
   value below. flex:1 1 0 gives every item an equal 1/n slot — so a long
   value (long Rambam / Chumash portions on heavy days) has to wrap INSIDE
   its own cell via .lb-val's line-clamp:3 rather than expanding the cell
   and forcing the whole bar to shrink its font. min-width:0 lets the
   flex item shrink below its content's intrinsic size so wrapping kicks
   in properly instead of overflowing. */
/* Learn-bar items use the same typography as the zmanim / shabbos /
   upcoming rows: label at body weight 500, value at body weight 700,
   both at 0.85 × --content-size. Each cell shrinks independently if
   its value would overflow (fitLearnBar); long values that can't fit
   at the shrink floor wrap to a second line via .lb-val-wrap. */
.lb-item{font-family:var(--font-body);font-size:calc(var(--content-size) * 0.75);white-space:nowrap;flex:1 1 0;min-width:0;color:var(--screen-fg);text-decoration:none;cursor:pointer;display:flex;flex-direction:column;align-items:center;justify-content:flex-start;gap:.15cqi;padding:0 .4em;}
.lb-item:hover{opacity:.7;}
/* Learn-bar label (Chumash / Tehilim / Tanya / …): uppercased to
   match the section-title voice (ZMANIM / SHABBOS / UPCOMING). Sits
   below the zmanim body band — never larger than the rows above. */
.lb-label{font-size:1em;font-weight:700;color:var(--screen-fg);line-height:1.25;display:block;max-width:100%;text-align:center;white-space:nowrap;text-transform:uppercase;letter-spacing:.5px;}
/* Learn-bar value (Nasso · 3rd / Chapters 18-22 / …): reads at the
   HaYom-Yom paragraph weight — plain body text, not bold. fitLearnBar
   wraps the value onto a second line via .lb-val-wrap when even the
   70 % floor isn't enough. */
.lb-val{font-size:1em;font-weight:400;line-height:1.3;white-space:nowrap;padding-bottom:2px;max-width:100%;text-align:center;}
.lb-val.lb-val-wrap{white-space:normal;overflow-wrap:break-word;line-height:1.2;}

/* ================================================================
   11 · SMALL-SCREEN LAYOUTS — narrow landscape, portrait, phones
   ================================================================ */
/* Narrow landscape: drop non-essential chrome so text doesn't clip.
   Portrait has its own layout and opts out via :not(.orient-portrait). */
@container (max-width: 600px){
  /* Drop the location stack (Chabad / city) and the brand-to-info dot so the
     brand wordmark has room without overflowing. */
  .screen:not(.orient-portrait) .tb-stack{display:none;}
  .screen:not(.orient-portrait) .tb-brand-dot{display:none;}
  /* Drop the English parsha and its separating dot, leaving just Hebrew. */
  .screen:not(.orient-portrait) .tb-parsha-eng{display:none;}
  .screen:not(.orient-portrait) .tb-parsha-dot{display:none;}
  /* Battery numeric — icon alone conveys status without the percent text. */
  .screen:not(.orient-portrait) .bat-pct{display:none;}
  /* Tighten zmanim/shabbos/upcoming column gap so the label column keeps
     more room before ellipsising. */
  .screen:not(.orient-portrait) .two-col-grid{--grid-col-gap:4px;--grid-cell-gap:4px;}
  /* Shrink learn-bar items proportionally so 6 items have a fighting chance
     of fitting a single row without clipping each other. */
  .screen:not(.orient-portrait) .lb-item{padding:0 .25em;}
}
@container (max-width: 460px){
  /* Topbar typography further downscaled so brand + parsha + ב״ה all fit. */
  .screen:not(.orient-portrait) .tb-brand{font-size:calc(var(--topbar-brand-size) * .78);}
  .screen:not(.orient-portrait) .tb-brand-heb{font-size:calc(var(--topbar-brand-size) * .82);}
  .screen:not(.orient-portrait) .tb-parsha-heb{font-size:calc(var(--topbar-parsha-size) * .78);}
  .screen:not(.orient-portrait) .tb-bh{font-size:calc(var(--topbar-brand-size) * .82);}
  .screen:not(.orient-portrait) .tb{gap:1%;}
}

/* Narrow landscape (≤ 700px container) — the 4:3 aspect lock + nowrap
   six-item learn-bar cannot fit readable text at this width. Drop the
   aspect lock, let the screen grow vertically, and wrap the learn-bar
   to multiple rows (same pattern portrait uses). Also shrink the
   two-col-grid labels statically so Zmanim / Shabbos / Upcoming fit
   without JS measurement. */
@container (max-width: 700px){
  .screen:not(.orient-portrait){
    aspect-ratio:auto;
    min-height:calc(100cqi * 0.6);
  }
  .screen:not(.orient-portrait) .body{position:relative;top:auto;left:auto;right:auto;bottom:auto;padding-bottom:0;min-height:100%;}
  .screen:not(.orient-portrait) .learn-bar{position:relative;bottom:auto;left:auto;right:auto;flex-wrap:wrap;row-gap:8px;column-gap:6px;padding:1.5% 0 1.5%;margin:auto var(--right-padding) 0 var(--left-padding);}
  .screen:not(.orient-portrait) .lb-item{flex:0 1 calc(33.333% - 6px);white-space:normal;gap:3px;padding:0 .3em;}
  .screen:not(.orient-portrait) .lb-label,
  .screen:not(.orient-portrait) .lb-val{white-space:normal;}
  .screen:not(.orient-portrait) .two-col-grid{--grid-col-gap:4px;--grid-cell-gap:4px;}
  .screen:not(.orient-portrait) .two-col-grid .zl,
  .screen:not(.orient-portrait) .two-col-grid .shl,
  .screen:not(.orient-portrait) .two-col-grid .up-l{font-size:.68em;}
  .screen:not(.orient-portrait) .two-col-grid .zt,
  .screen:not(.orient-portrait) .two-col-grid .sht,
  .screen:not(.orient-portrait) .two-col-grid .up-d{font-size:.72em;}
}

/* Portrait / vertical-screen layout — natural flow so the screen shrinks to
   content (no forced aspect ratio means no dead space when content is short).
   No max-height: the screen grows to fit Zmanim + Shabbos + HaYom Yom + Omer
   + learn-bar without clipping. The page scrolls if the shell outruns the
   viewport; clipping looked like a bug (e.g. Zmanim rows vanishing). */
.screen.orient-portrait{
  aspect-ratio:auto;
  display:flex;
  flex-direction:column;
  --section-gap:1.6%;
  /* Portrait rows read tighter than landscape at the same leading (the
     stacked card has no aspect lock), so pull the row line-height down a
     step. Col/row gaps stay at the .screen defaults (8px / 4px). */
  --grid-row-lh:1.3;
}
.shell.orient-portrait{
  max-width:calc((100vh - 140px) * 1404 / 1872 + 24px);
  margin-left:auto;
  margin-right:auto;
}
/* Short-landscape phones share the portrait stacked layout, but the
   .shell max-width above is viewport-height-based — at ~390px tall it
   collapses to a ~174px sliver. Drop the cap so the shell spans the
   full viewport width. */
.shell.orient-portrait.orient-short-landscape{max-width:none;width:100%;}
/* Un-absolute the top bar, body, and learn-bar so they flow vertically. */
.screen.orient-portrait .tb{position:relative;top:auto;left:auto;right:auto;height:auto;margin:2% 2% 0;padding:2% var(--left-padding);flex:0 0 auto;flex-wrap:wrap;row-gap:4px;column-gap:12px;justify-content:space-between;border-radius:10px;}
/* Portrait parsha: share the top-bar row with the Chabad stack. .tb-r
   may be empty on iOS (battery hidden when navigator.getBattery is
   missing). flex:1 1 auto lets the
   parsha fill whatever space the stack leaves; min-width:0 +
   overflow:hidden let it shrink / clip on very narrow phones rather
   than push the stack off-screen. If it still can't fit, the parent's
   flex-wrap:wrap drops it to a second line — the 12px column-gap on
   .tb keeps a visible buffer between the stack and the parsha in both
   cases. */
/* Portrait bar: hide the battery pill and drop the whole .tb-r group
   (clock + calendar pill). The clock is NOT in the bar in portrait —
   placeClock() moves it down into .clock-portrait-slot (below). With
   .tb-r gone, .tb has just two flex children — .tb-l (Chabad stack) at
   the left and .tb-c (parsha) growing to the right — so the parsha hugs
   the right edge sharing the row with the stack, exactly like the
   original portrait layout. */
.screen.orient-portrait .bat-wrap{display:none;}
.screen.orient-portrait .tb-r{display:none;}
/* PORTRAIT CLOCK — the big centered clock below the bar (the original
   layout). Empty + collapsed in landscape (clock lives in the topbar
   there); filled by placeClock() in portrait. cqi sizes match the old
   .clock-row so portrait reads exactly as it did before the topbar
   move. */
.clock-portrait-slot{display:none;}
.screen.orient-portrait .clock-portrait-slot{
  display:flex;align-items:flex-end;justify-content:center;
  flex-shrink:0;margin:2.5% 0 4.5%;
}
.screen.orient-portrait .clock-portrait-slot .tb-clock{gap:0.5cqi;}
.screen.orient-portrait .clock-portrait-slot .ct{font-size:clamp(36px,5.75cqi,200px);line-height:.88;letter-spacing:-1px;}
.screen.orient-portrait .clock-portrait-slot .ap{font-size:clamp(15px,2.25cqi,80px);padding-bottom:.4cqi;}
/* The BASE .tb-c rule absolutely-positions the cell at 50%/50% of .tb
   with a centering transform. Undo every piece of that absolute-
   centering so .tb-c becomes a real flex child of .tb. flex:1 1 auto
   lets it share the row with .tb-l and grow to fill the remaining
   width; justify-content:flex-end then pins the parsha against the
   right edge of that row. Parsha font is tuned (at phone @media,
   below) to fit this remaining width. */
.screen.orient-portrait .tb-c{
  position:static;
  left:auto;top:auto;
  transform:none;
  max-width:none;
  flex:1 1 auto;
  min-width:0;
  overflow:hidden;
  justify-content:flex-end;
}
/* Parsha forced to a single line (nowrap); renders flush against the
   right edge of the bar, sharing the row with the Chabad stack.
   .tb-parsha-eng keeps normal wrapping in case a future dual-language
   row reuses that slot. */
.screen.orient-portrait .tb-parsha-heb{white-space:nowrap;}
.screen.orient-portrait .tb-parsha-eng{white-space:normal;}
.screen.orient-portrait .body{position:relative;top:auto;left:auto;right:auto;bottom:auto;padding-bottom:0;flex:1 1 auto;min-height:0;}
.screen.orient-portrait .body-main{flex:0 1 auto;flex-direction:column;}
.screen.orient-portrait .L{width:100%;padding:2% var(--left-padding) .6% var(--left-padding);justify-content:flex-start;}
/* Portrait — the L panel grows tall with the stacked R panel beside it,
   so the landscape "push the bottom stack flush against the learn-bar"
   rule would leave an awkward empty gap. Disable the auto-margin in
   portrait so the bottom stack flows immediately after the static
   sections like every other child. */
/* Portrait — release the vertical-center grab on .L-content (the L
   column grows tall stacked above the R panel, so flex:1 + center
   would leave awkward gaps) and let the clock take its natural height. */
.screen.orient-portrait .L-content{flex:0 1 auto;justify-content:flex-start;}
/* Portrait header — give the clock/date/occasion stack air and a clear
   size ladder (clock > date > occasion). Landscape grows the date to
   fill its column; portrait keeps it at this fixed, calmer size.
   Bottom margin = L padding-top (2%) + this margin-top (2.5%) so the
   clock sits centered between the gray bar above and the date below.
   The phone breakpoint uses a larger L padding-top, so it overrides
   the bottom margin to match (see the phone @media block). */
.screen.orient-portrait .date-line{font-size:calc(var(--edate-size) * 1.1);line-height:1.4;margin-bottom:.6%;}
/* Occasion + daily-notes match the zmanim row line-height (1.33) and
   carry no extra bottom margin, so the gap from the date block down to
   ZMANIM is the same rule spacing as every section-to-section gap
   below it — one uniform rhythm the whole way down. */
.screen.orient-portrait .occasion{line-height:1.33;row-gap:.15em;}
.screen.orient-portrait .daily-notes{margin:.7% 0 0;gap:.3em;}
.screen.orient-portrait .R{width:100%;padding:.6% var(--right-padding) 1% var(--right-padding);justify-content:flex-start;}
/* Portrait stacks the two columns, which would turn the column divider
   into a horizontal line between UPCOMING and HAYOM-YOM — hide it; the
   divider is only needed side-by-side in landscape. */
.screen.orient-portrait .vdiv{display:none;}
.screen.orient-portrait .learn-bar{position:relative;bottom:auto;left:auto;right:auto;flex:0 0 auto;flex-wrap:wrap;row-gap:12px;padding:2.5% 0 3%;margin:0 var(--right-padding) 0 var(--left-padding);justify-content:space-between;column-gap:8px;}
/* Portrait type — body tier flows from :root --content-size via the
   container's clamp() floor. The only portrait-specific overrides
   below are for spacing (layout breathing room on narrow widths) —
   NOT for font-size. The body tier (zmanim/shabbos/upcoming rows,
   learn-bar labels+values, occasion, daily-notes, sec-pa, omer Hebrew
   lines) all resolve to the same floor value at narrow viewports. */
.screen.orient-portrait .lb-item{flex:0 1 31%;min-width:0;text-align:center;padding:0 .3em;white-space:normal;gap:3px;}
.screen.orient-portrait .lb-label,
.screen.orient-portrait .lb-val{white-space:normal;}
/* Portrait Omer Hebrew — stays one line via fitOmerLines shrink-to-fit.
   Wrap to multiple lines would break the visual rhythm of the block. */
.screen.orient-portrait .hy-lbl{margin-bottom:8px;}
.screen.orient-portrait .omer-block{padding:20px 0 6px;margin-top:4px;gap:6px;}
.screen.orient-portrait .omer-title{margin-bottom:6px;}
.screen.orient-portrait .learn-bar{row-gap:14px;padding:3% 0 3.5%;}

/* ================================================================
   12 · LOADING SPLASH
   ================================================================ */
.loading{position:absolute;inset:0;background:#fff;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:10px;z-index:50;}
/* Portrait .screen is content-driven (aspect-ratio:auto) so it would collapse
   to 0px while the only child is the absolute-positioned .loading overlay.
   Give it the full portrait height during load so the splash is visible. */
.screen.orient-portrait:has(>.loading){min-height:calc(100vh - 140px);}
.lheb{font-family:var(--font-hebrew);font-size:52px;animation:pulse 2s ease-in-out infinite;}
.ltxt{font-family:var(--font-body);font-size:11px;letter-spacing:2px;color:var(--screen-fg);text-transform:uppercase;text-align:center;max-width:80%;}
@keyframes pulse{0%,100%{opacity:1}50%{opacity:.2}}

/* Phone-sized viewports — optimize vertical/portrait layout so the dashboard
   fills the screen instead of sitting in a small box, and bump fonts/spacing
   for comfortable reading at device-width. */
@media (max-width: 600px){
  body{overflow-x:hidden;}
  /* Mobile: keep the rounded black rim (shell padding 8 + screen radius
   10 = shell radius 18, concentric). */
  .wrap{padding:12px;gap:6px;justify-content:flex-start;min-height:100svh;}
  /* Rounded like landscape but gentler — big radii clash with the
     gray top bar's curve at phone size. Screen radius 10 + shell
     padding 8 = shell radius 18, concentric. */
  .shell{padding:8px;border-radius:18px;box-shadow:0 2px 6px rgba(0,0,0,0.25),0 10px 30px rgba(0,0,0,0.4);}
  :root{--screen-radius:10px;}
  .shell.orient-portrait{max-width:none;width:100%;}
  /* Phone toolbar: 9 buttons must fit one row at iPhone-portrait width.
   Download / fullscreen / year-export are hidden below; icons clamp
   26–32 px so they shrink on narrow phones without dropping below a
   comfortable tap size. */
  .nav{padding:0 8px 8px;gap:2px;flex-wrap:nowrap;row-gap:4px;}
  #dl-btn,#fs-btn,#gy-btn{display:none;}
  .info-panel{font-size:12px;}
  .info-panel summary{padding:8px 12px;}
  .info-body{padding:2px 14px 12px;}
  .nav-items{display:contents;}
  .nav-items[hidden]{display:none;}
  /* Mobile: brand stays on the same row as the hamburger (margin-left:
     auto from the base .nav-brand rule floats it to the right edge).
     Tighter font + gap so "bayit.info · בַּיִת · ב״ה" fits alongside
     the 32-px hamburger at 320 px widths. */
  .nav-brand{font-size:15px;gap:6px;}
  /* When the menu is open (nav-items not [hidden]), the icon row
     expands via display:contents and fills the width — hide the brand
     so the menu items have room. Closing the menu restores it. */
  .nav:has(#nav-items:not([hidden])) .nav-brand{display:none;}
  /* 10 icon buttons + Today (the theme toggle joined the row) must
     fit ONE line down to 320px-wide phones — never wrap. */
  /* Size = (row width - Today button - gaps) / 10 icons, so the row
     FILLS the line edge to edge instead of huddling left; capped at a
     tasteful 34px on the widest phones. */
  .nb{height:clamp(20px, calc((100vw - 105px) / 10), 34px);padding:0 6px;font-size:12px;}
  .nb-ico{width:clamp(20px, calc((100vw - 105px) / 10), 34px);min-width:clamp(20px, calc((100vw - 105px) / 10), 34px);height:clamp(20px, calc((100vw - 105px) / 10), 34px);font-size:20px;padding:0;}
  .date-combo-ico{width:clamp(20px, calc((100vw - 105px) / 10), 34px);min-width:clamp(20px, calc((100vw - 105px) / 10), 34px);height:clamp(20px, calc((100vw - 105px) / 10), 34px);}
  .date-combo-ico .cal-icon,.nb-ico .cal-icon{width:58%;height:58%;}
  .screen.orient-portrait{
    max-height:none;
    /* No min-height floor here: the portrait card sizes to its content
       (aspect-ratio:auto). A previous `min-height:calc(100svh - 110px)`
       forced near-full phone height regardless of content, so on sparse
       days the surplus pooled below the learn-bar as a bottom gap. The
       tradeoff: a light day no longer fills the whole phone screen.
       The :has(>.loading) floor below still gives the splash full height. */
    --section-gap:1.8%;
    /* Tighten topbar typography on phone portrait so brand+location and
       parsha each fit one row instead of wrapping into 4-5 visual lines.
       cqi units would resolve against the narrow phone width and shrink
       these tokens too aggressively; lock them to small fixed px instead. */
    --topbar-brand-size:18px;
    --topbar-parsha-size:20px;
    --topbar-loc-size:11px;
  }
  .screen.orient-portrait:has(>.loading){min-height:calc(100svh - 110px);}
  /* Phone portrait: tighten right-padding so the (now right-aligned)
     parsha can reach the edge of the gray bar instead of sitting
     var(--left-padding) in from it. 8px keeps a small buffer from
     the 10px border-radius of the bar so the glyph doesn't touch the
     rounded corner. */
  /* Side padding is larger than top/bottom to compensate for the
     parsha's line-height leading (~3.5px each side): that leading
     already pushes the visible Hebrew glyphs in from the top/bottom
     edges, so the wider side padding makes the visible gap equal on
     all four sides. */
  .screen.orient-portrait .tb{padding:2.5% 3.6% 2.5% 3.6%;row-gap:4px;}
  .screen.orient-portrait .tb-stack{gap:0;}
  /* Bump the location stack ("Chabad / Los Angeles 90036") ~25 % in
     portrait — the topbar has more room there and the smaller line at
     base size reads cramped next to the parsha glyphs. */
  .screen.orient-portrait .tb-stack .tb-nusach,
  .screen.orient-portrait .tb-stack .tb-loc{font-size:calc(var(--topbar-parsha-size) * 0.375);}
  .screen.orient-portrait .tb-parsha-heb,
  .screen.orient-portrait .tb-parsha-eng{line-height:1.2;}
  .screen.orient-portrait .L{padding:3.5% var(--left-padding) 1.5% var(--left-padding);}
  /* Phone L padding-top is 3.5%, so bottom margin = 3.5% + 2.5% = 6%
     keeps the clock centered between the gray bar and the date. */
  .screen.orient-portrait .R{padding:1.5% var(--right-padding) 2.5% var(--right-padding);}
  /* Phone portrait — readable but compact. Narrower viewport, so px values
     that felt good on tablet portrait end up oversized here and wrap the
     multi-word learn-bar items (e.g. "Prayer and the Priestly Blessing,
     Ch. 14") onto many lines. */
  /* Phone portrait: hard-pin the learn-bar to a 3-column grid so the six
     cells wrap onto exactly two rows (CHUMASH TEHILIM TANYA /
     RAMBAM 1 RAMBAM 3 DAF YOMI). The parent portrait rule uses
     display:flex + flex-wrap:wrap + justify-content:space-between; on
     narrow phone widths that pairing would sometimes round a 30%
     flex-basis up and push only two items per row, leaving three rows.
     Grid with repeat(3, 1fr) is deterministic — !important is required
     to win over the flex display from line 436. */
  .screen.orient-portrait .learn-bar{
    display:grid !important;
    grid-template-columns:repeat(3, minmax(0, 1fr));
    column-gap:8px;
    row-gap:12px;
    /* No side padding — the bar's own left/right margins already match
       the section padding, so CHUMASH / RAMBAM 1 line up with ZMANIM. */
    padding:3.5% 0 4%;
  }
  /* Phone portrait font-sizes flow from :root's clamp() floors — no
     per-element overrides. The body tier (zmanim/shabbos/upcoming
     rows, learn-bar, occasion, daily-notes, omer Hebrew lines) all
     resolve to the same 15 px floor. Only LAYOUT tweaks (grid cell
     count, column-gap) belong here. */
  .screen.orient-portrait .lb-item{flex:unset;min-width:0;padding:0 .3em 0 .8em;gap:2px;}
  /* First column of the 3-wide grid sits flush with the section edge:
     no hairline, no left padding (mirrors the :first-child rule that
     handles this in the single-row landscape bar). background:none is
     load-bearing — the dotted divider is PAINTED via background-image
     (--sep-dots-v), not the (transparent) border, so clearing only
     border-left left a stray dotted line beside RAMBAM 1 (Joseph's
     2026-07-23 screenshot). */
  .screen.orient-portrait .lb-item:nth-child(3n+1){border-left:none;background:none;padding-left:0;}
  /* Grid spacing comes from the --grid-* tokens (defaults on .screen,
     portrait line-height on .screen.orient-portrait) — no overrides here. */
  .lheb{font-size:64px;}
  .ltxt{font-size:12px;}
  .zip-box{padding:28px 24px;min-width:0;width:100%;}
  .zip-title{font-size:30px;}
  .zip-input,.zip-suggestions{width:100%;max-width:280px;}
  .dp-pop{width:calc(100vw - 32px);max-width:320px;}
  .sh-pop{width:calc(100vw - 32px);max-width:260px;}
}

/* ================================================================
   13 · TYPE WEIGHTS & PNG-CAPTURE TWEAKS
   The PNG uses the SAME weights and colors as the live page — the
   download must mirror the website exactly (only the firmware
   keep-outs — clock and battery % — and px-unit scale compensation
   may differ). The old .capture-mode ExtraBold-800 blanket that
   bolded the export was removed for that reason; don't reintroduce
   capture-only typography.
   ================================================================ */

/* Omer sefira pair (the חֶסֶד שֶׁבְּתִפְאֶרֶת label next to the English
   title) matches the bracha / HaRachaman body lines — same medium
   weight (500), no paint-stroke. Only the day-count line carries the
   heavier 700 so it reads as the focal line without dominating. */
.omer-sefira{
  font-weight:500;
  font-variation-settings:"wght" 500;
}
/* Hebrew header date + Hebrew parsha: Black 900 for visual weight
   parity with their English counterparts on the same row. */
.hdate,
.tb-parsha-heb{
  font-weight:900;
  font-variation-settings:"wght" 900;
}
/* Brand-stripe Hebrew (בַּיִת + ב״ה): SemiBold 600 reads as a chrome
   wordmark rather than competing with the Hebrew parsha. */
.tb-brand-heb,
.tb-bh{
  font-weight:600;
  font-variation-settings:"wght" 600;
}

/* html2canvas compatibility (active only while the PNG is being
   rasterized): paint-order isn't implemented, so the live -webkit-
   text-stroke on the parsha would overprint the glyph interior at
   bold weights. text-shadow gives the same white halo without the
   overprint. Also relax the .tb-c clip — html2canvas snaps the paint
   bounds tightly and trims glyph ascenders inside an overflow-x:clip
   container even when the live browser renders fine. */
.capture-active .tb-c{overflow:visible !important;}
/* Capture-only: rounder topbar corners in the downloaded PNG. The
   live web view keeps the modest 14px radius defined on .tb. */
.screen.e-paper-capture .tb{border-radius:calc(var(--tb-radius,26px) * 2.34);}
/* Capture-only: enlarge the charging bolt 2× and widen + heighten the
   battery pill so the bigger bolt and a 3-character "##%" both fit
   comfortably with breathing room on each side. Live web view keeps
   the compact bolt + pill. The pill + bolt render in the PNG; only
   the .bat-pct percentage (class .firmware-overlay) is blanked — the
   device firmware draws the live % into that gap. */
.screen.e-paper-capture .bat-wrap{padding:10px 22px;gap:6px;}
.screen.e-paper-capture .bat-wrap > svg{width:22px;height:36px;}
/* Capture-only: html2canvas mis-paints box-shadow — it washes the
   shadow color across the pill's interior (white pill renders ~#eee
   with the children's boxes floating pure-white inside it) and draws
   a dark band under the bottom edge. The shadows are a subtle web
   nicety; drop them during capture so the pills render clean white. */
.screen.e-paper-capture .bat-wrap,
.screen.e-paper-capture .tb-cal-btn,
.screen.e-paper-capture .yc-btn{box-shadow:none;}
/* Capture-only: the TODAY chip marks today in the live calendar view,
   but a printed/e-paper month grid must not pin "Today" to the day the
   PNG happened to be generated on. */
.screen.e-paper-capture .yc-today-lbl{display:none;}
/* Equal-width learn-bar cells in BOTH the live web view (wide
   landscape) AND the downloaded PNG so the sub-headers (CHUMASH /
   TEHILIM / TANYA / RAMBAM 1 / RAMBAM 3 / DAF YOMI) sit at evenly
   spaced centers across the bar. fitLearnBar's default behaviour is
   to boost flex-grow on cells whose value wraps to >2 lines (so they
   claim more bar width), which makes the labels unevenly spaced.
   !important wins against the inline style.flexGrow that fitLearnBar
   writes. Long values still wrap inside their cell; they just don't
   get a width boost. Scoped via @container (min-width: 701px) so the
   narrow-landscape (<=700px) and portrait phone layouts — which use
   their own flex:0 1 33% wrap rules — are untouched. */
/* Each learn-bar cell sized to its OWN content (the title + the value
   wrap), not to a fixed equal-flex slot. The cells are then spread
   across the bar by .learn-bar's existing justify-content:space-between
   so the gaps between cells are equal. Net effect: a cell with a long
   value (e.g. RAMBAM 1 "The Order of Prayer, Ch. 4") naturally claims
   more horizontal room than a cell with a short value (e.g. DAF YOMI
   "Chullin 21"). The title inside each cell stays centered above its
   own value because .lb-item still has align-items:center.

   !important overrides the inline style.flexGrow that fitLearnBar
   writes when a value wraps to >2 lines. Scoped to wide-landscape so
   the narrow (<=700) and portrait phone layouts keep their own
   3-column wrap rules. */
@container (min-width: 701px){
  .screen:not(.orient-portrait) .lb-item{flex:0 1 auto !important;}
}

/* ================================================================
   13b · ALMANAC SKIN — calmer, editorial restyle of the day view
   Same information, lighter visual weight: hairline rules instead
   of heavy black bars, muted tracked section labels, dotted
   "ledger" baselines under the time rows, tabular-aligned times,
   and a roomier HaYom-Yom reading column.
   ================================================================ */
/* Clock — tabular figures keep the colon column steady; am/pm reads
   as a quiet caption. */
.ct{font-weight:400;letter-spacing:0;font-variant-numeric:tabular-nums;}
.ap{font-weight:600;color:var(--alm-ink);}
/* Date line — the hero. The separator fades so the English + Hebrew
   dates read as one balanced unit. */
.edate{font-weight:600;color:var(--alm-ink);}
.date-sep{opacity:1;color:#000;}
/* Occasion + halachic notes — calm secondary ink. */
.occasion,.occ-item{color:var(--alm-ink);}
.note-line{color:var(--alm-ink);font-weight:500;}
.insertion-line{color:var(--alm-ink);}
/* Section kickers (ZMANIM / SHABBOS / UPCOMING / HAYOM-YOM / OMER)
   — tracked and muted, at the SAME size as the content text under
   them (the gray + tracking differentiates; size stays uniform). */
.sec,.hy-lbl,.omer-title{
  font-size:var(--content-size);
  letter-spacing:2.4px;
  font-weight:700;
  color:var(--alm-muted);
}
.sec-pa,.molad-pa{color:var(--alm-muted);font-weight:600;letter-spacing:.3px;}
/* Full-width section rules removed — the whitespace + gray kicker
   labels separate sections; the dotted ledger rows carry structure. */
.rule{margin-top:calc(var(--section-gap) * 1.1);border-top-color:transparent;}
/* Zmanim / Shabbos / Upcoming — ledger rows: a faint dotted baseline
   under each row makes the block scannable; times align with
   tabular figures. */
.zrow,.shrow,.up-row{
  border-bottom:var(--sep-weight) solid transparent;
  background-image:var(--sep-dots-h);
  background-origin:border-box;background-clip:border-box;
  background-position:left bottom;
  background-size:var(--sep-period) var(--sep-weight);
  background-repeat:repeat-x;
  align-items:baseline;
}
/* The L column's LAST rendered line drops its dotted baseline —
   nothing follows for it to separate (Joseph, 2026-07-24). Marked by
   fitLastBaseline() as .row-last on the rows sharing the last VISIBLE
   line of the last visible grid — a JS pass because :nth-last-child
   can't see rows fitUpcoming hid with display:none. Landscape only
   (the pass skips portrait, where the flow continues into HaYom-Yom
   and the baseline stays as the separator). */
.zrow.row-last,.shrow.row-last,.up-row.row-last{border-bottom:none;background:none;}
/* Blocks relocated into the R column (Fast at the top, Shabbos on
   dense days): the .rule that travels with the block renders as a
   VISIBLE dotted separator there — "a dotted line between HaYom-Yom
   and the Shabbos info" (Joseph, 2026-07-24) — while in the L column
   rules stay invisible spacers. The moved grid's last visual line
   drops its own baselines (.row-noline, marked by the move fits) so
   the block ends with one line, never two. */
.R .rule{border-top:var(--sep-weight) solid transparent;background-image:var(--sep-dots-h);background-origin:border-box;background-clip:border-box;background-position:left top;background-size:var(--sep-period) var(--sep-weight);background-repeat:repeat-x;
  /* Margins mirror the L column's section rhythm (Joseph: "spacing
     should match the spacing between Zmanim and Upcoming"): the
     dotted line hugs the content above it like a row baseline, and
     the full section gap sits BELOW it, before the next header. */
  margin:1% 0 calc(var(--section-gap) * 1.1);}
.zrow.row-noline,.shrow.row-noline,.up-row.row-noline{border-bottom:none;background:none;}
.zl,.shl,.up-l{color:var(--alm-ink);font-weight:400;}
.zt,.sht,.up-d{color:var(--alm-ink);font-weight:600;font-variant-numeric:tabular-nums;}
.omer-count-line{color:var(--alm-ink);}
/* HaYom-Yom — a proper reading column: roomier leading, calm ink. */
.hy-text{font-weight:400;line-height:1.72;color:var(--alm-ink);}
.hy-part-lbl{color:var(--alm-ink);}
/* The "Repeat of Cheshvan/Kislev/Adar 29 - No entry…" note is an
   explanatory aside, not a section heading like Adar I / Adar II — so
   it renders at the normal reading weight, not bold. */
.hy-part-lbl-note{font-weight:400;font-variation-settings:"wght" 400;}
/* Learning bar — refined footer. Its top rule (separating HaYom-Yom
   from the learning) and the thin dividers between the six portions
   are DOTTED, matching the zmanim ledger lines so every separator on
   the screen reads as one consistent treatment. */
.learn-bar{border-top:var(--sep-weight) solid transparent;background-image:var(--sep-dots-h);background-origin:border-box;background-clip:border-box;background-position:left top;background-size:var(--sep-period) var(--sep-weight);background-repeat:repeat-x;}
.lb-item{border-left:var(--sep-weight) solid transparent;background-image:var(--sep-dots-v);background-origin:border-box;background-clip:border-box;background-position:left top;background-size:var(--sep-weight) var(--sep-period);background-repeat:repeat-y;align-items:flex-start;padding-left:1.1em;}
.lb-item:first-child{border-left:none;background:none;padding-left:0;}
.lb-label{color:var(--alm-faint);font-weight:700;letter-spacing:1.1px;text-align:left;}
.lb-val{color:var(--alm-ink);font-weight:400;text-align:left;}
/* Omer top rule — dotted like every other separator on the screen. */
.omer-block{border-top:var(--sep-weight) solid transparent;background-image:var(--sep-dots-h);background-origin:border-box;background-clip:border-box;background-position:left top;background-size:var(--sep-period) var(--sep-weight);background-repeat:repeat-x;}
/* When the Omer sits in the L column (landscape — fitMoveOmer parks it
   among the ledger sections), the grid row directly above it already
   draws a dotted baseline, so the Omer's own top border would make a
   redundant double line. Drop it there and let the section's baseline
   be the single separator; a modest top margin keeps breathing room. */
.L-content .omer-block{border-top:none;background:none;margin-top:calc(var(--section-gap) * 1.1 + 0.8%);}

/* PNG capture intentionally keeps the Almanac skin AS-IS — the muted
   gray kickers (#767676 / #9a9a9a) and the dotted ledger baselines
   render in the export exactly as they do on the website. (A capture
   override that forced them solid black / removed the dots was tried
   and reverted by request — the device PNG should mirror the web skin,
   with only the firmware keep-outs and html2canvas shadow bugs
   special-cased below in section 13.) */
/* Capture-only: SCALE compensation, not styling. Border widths are CSS
   px and don't scale with the container, so at the 1872px capture the
   live 2.25px rules would read half as thick as they do on the ~932px
   web card. Double the width (2.25 → 4.5px) so the PNG shows the SAME
   apparent hairline as the website; the color and dotted style are
   inherited untouched from the skin rules above — the export must
   mirror the web exactly. */
.screen.e-paper-capture{
  --sep-weight:4.5px;  /* thickness compensation, as before */
  /* Integer dot/gap so every dot lands on whole pixels at the pinned
     1872px layout — the same 4-on/4-off rhythm the column divider has
     always rendered with, now locked for every dotted line. */
  --sep-dot:4px;
  --sep-gap:4px;
}
/* Pixel-snap the topbar in capture: 9.45% of 1404 is fractional, so
   the dotted rule's bottom edge straddled a half-pixel and its dots
   smeared across three antialiased rows (visibly lighter than the
   learn-bar's). Integer top+height put the dots on whole pixels. */
.screen.e-paper-capture .tb{top:0;height:166px;}
/* Pill + grid strokes double for the 1872px capture, matching the
   rule-weight doubling above — on the website (~930px wide) the same
   1–1.5px borders read proportionally twice as heavy. */
.screen.e-paper-capture .bat-wrap,
.screen.e-paper-capture .tb-cal-btn,
.screen.e-paper-capture .yc-btn{border-width:3px;}
.screen.e-paper-capture .jf-chip,
.screen.e-paper-capture .jf-plabel,
.screen.e-paper-capture .jf-btn{border-width:3px;}
.screen.e-paper-capture .yc-day{border-top-width:2px;border-right-width:2px;}
.screen.e-paper-capture .yc-dow-hdr{border-bottom-width:3px;}
/* .lb-item / .vdiv / .omer-block dotted rules scale through the
   --sep-* capture overrides above — no per-element width bumps. */

/* ================================================================
   14 · MONTH CALENDAR OVERLAY (yc-…) — drawn over the screen
   Frameless, square-cornered grid of day cells: hairline gray
   separators only, gray Saturday rest-day band, gray boxes on major
   holidays, a 2px inset black ring on today, inverted (black) cell
   for the selected day.
   ================================================================ */
/* z-index:20 keeps the opaque calendar above the dashboard topbar
   (.tb, z-index:10). openYearCal() hides .tb, but a render() firing
   while the calendar is open (e.g. tick()'s midnight auto-advance, or a
   nightfall boundary crossing) rebuilds .tb visible; at equal z-index
   it would paint the parsha/location strip over the calendar's own
   header. Stacking only — no layout change, and the PNG export never
   renders the overlay, so the device month output is untouched. */
.yc-overlay{position:absolute;inset:0;display:flex;flex-direction:column;background:var(--screen-bg);z-index:20;}
.yc-overlay[hidden]{display:none;}
.yc-inner{width:100%;height:100%;display:flex;flex-direction:column;color:var(--screen-fg);font-family:var(--font-body);}
/* Topbar — same height/gray as the dashboard topbar */
.yc-topbar{flex-shrink:0;margin:0.9% var(--right-padding) 0 var(--left-padding);background:transparent;border-radius:var(--tb-radius,26px);height:var(--topbar-height);display:flex;align-items:center;justify-content:space-between;padding:0 8px;}
/* Calendar buttons — crisp white pills with a hairline border,
   matching the dashboard's white battery pill. */
.yc-btn{background:#fff;border:1.5px solid #000;color:var(--topbar-fg);padding:0 1cqi;height:3cqi;display:inline-flex;align-items:center;justify-content:center;gap:0.45cqi;font-family:var(--font-body);font-size:calc(var(--topbar-loc-size) * 0.85);font-weight:700;letter-spacing:0.06cqi;cursor:pointer;border-radius:100px;white-space:nowrap;text-transform:uppercase;box-shadow:0 1px 2px rgba(0,0,0,0.08);transition:background .1s,border-color .1s;}
.yc-btn:hover{background:#f1f1f1;border-color:#000;}
.yc-btn:active{background:#e6e6e6;}
/* TODAY matches the shared 6.6cqi × 3cqi pill size (battery, calendar). */
#yc-today{width:6.6cqi;padding:0;box-sizing:border-box;}
/* Prev / next arrows — same white pill, rendered as a circle. */
.yc-btn-ico{padding:0;width:3cqi;min-width:3cqi;height:3cqi;border-radius:50%;font-size:calc(var(--content-size) * 0.68);line-height:1;}
.yc-btn-ico svg{width:1.3cqi;height:1.3cqi;display:block;}
/* Left: battery pill · Center: arrow | title | arrow · Right: TODAY */
.yc-tb-left{display:flex;align-items:center;flex:1;min-width:0;position:relative;}
.yc-tb-center{display:grid;grid-template-columns:auto minmax(0,1fr) auto;align-items:center;gap:0.8cqi;}
.yc-title-stack{display:flex;flex-direction:column;align-items:center;justify-self:center;width:calc(var(--topbar-parsha-size) * 7);text-align:center;}
.yc-title-eng{font-family:var(--font-display);font-size:calc(var(--topbar-parsha-size) * 0.62);line-height:1.05;white-space:nowrap;letter-spacing:-0.005em;}
.yc-mo{font-weight:700;}
.yc-yr{font-weight:700;margin-left:0.16em;}
.yc-heb-yr{margin-inline-start:0.16em;}
.yc-title-heb{font-family:var(--font-hebrew);font-size:calc(var(--topbar-parsha-size) * 0.58);font-weight:700;letter-spacing:0.01em;white-space:nowrap;direction:rtl;margin-top:0.3em;line-height:1.1;}
.yc-tb-right{display:flex;align-items:center;gap:0.8cqi;flex:1;min-width:0;justify-content:flex-end;}
/* Today in the month header is retired chrome (Joseph, 2026-07-23):
   hidden everywhere — landscape has the toolbar's own Today button,
   and in phone portrait the app bar above the calendar already
   carries Today, so the month header showing it twice just crowded
   the ◀ title ▶ / JUMP row. The pinned e-paper capture force-hides
   it as before (1872x1404 month artifact stays byte-identical). */
.yc-today-btn{display:none;}
.screen.e-paper-capture .yc-today-btn{display:none !important;}
#yc-jump{width:6.6cqi;padding:0;}
/* DOW header — quiet uppercase labels over a strong baseline rule */
.yc-dow-hdr{display:grid;grid-template-columns:repeat(7,1fr);text-align:center;font-size:calc(var(--content-size) * 0.62);color:var(--screen-fg);font-weight:600;text-transform:uppercase;letter-spacing:0.18cqi;padding:0.75% 0;flex-shrink:0;border-bottom:1.5px solid var(--screen-fg);margin:0 0.9%;}
/* Day grid — frameless and square-cornered: no outer border, only
   hairline interior separators (each cell draws its own top + right
   line; the first row and last column suppress theirs). */
.yc-days{display:grid;grid-template-columns:repeat(7,1fr);grid-template-rows:repeat(6,1fr);flex:1;border:none;border-radius:0;overflow:hidden;margin:0 0.9% 0.9%;}
.yc-day{position:relative;display:flex;flex-direction:column;align-items:stretch;background:var(--screen-bg);cursor:pointer;color:var(--screen-fg);font-family:var(--font-body);overflow:hidden;padding:0.6cqi 0.7cqi 0.5cqi;border:none;border-top:1px solid var(--topbar-bg);border-right:1px solid var(--topbar-bg);transition:background .08s;}
.yc-day:nth-child(-n+7){border-top:none;}
/* Shabbos (Saturday) column + major holidays — rest-day band in the
   top-bar gray. Adjacent-month (trailing) cells stay white so their
   faded day numbers remain legible. */
.yc-day:nth-child(7n){background:var(--topbar-bg);border-right:none;}
.yc-day.yc-hol{background:var(--topbar-bg);}
.yc-day.trailing{background:var(--screen-bg);}
.yc-day:hover{background:#ededed;}
/* Top row: Gregorian day (left) + Hebrew day (right), a TODAY chip
   between them on the current day */
.yc-day-top{display:flex;align-items:baseline;justify-content:space-between;flex-shrink:0;gap:0.4cqi;position:relative;}
/* TODAY is pinned to the exact center of the number row — absolute,
   so its spot never shifts with the width of the date numerals. */
.yc-today-lbl{position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);font-size:calc(var(--content-size) * 0.63);font-weight:800;text-transform:uppercase;letter-spacing:0.1cqi;color:var(--screen-fg);white-space:nowrap;}
.yc-gd{font-weight:700;font-size:calc(var(--content-size) * 1.28);line-height:1;letter-spacing:-0.02cqi;}
.yc-hd{font-weight:700;font-size:calc(var(--content-size) * 1.28);font-family:var(--font-hebrew);direction:rtl;line-height:1;color:var(--screen-fg);}
/* Event stack under the date */
.yc-cell-body{display:flex;flex-direction:column;justify-content:flex-end;gap:0.3cqi;margin-top:0.45cqi;overflow:hidden;flex:1;min-height:0;}
/* Parsha — italic serif, on top of the Shabbos stack */
.yc-parsha{font-size:calc(var(--content-size) * 0.68);font-style:italic;font-weight:600;color:var(--screen-fg);line-height:1.3;text-align:left;overflow:hidden;white-space:nowrap;text-overflow:ellipsis;}
/* Titles — holidays, Rosh Chodesh, Chabad occasions */
/* line-height 1.3, NOT tighter: these boxes clip (overflow:hidden /
   line-clamp), and serif descenders (g p y) need the taller line box
   or they're cut - same fix the learn-bar labels carry. */
.yc-title{font-size:calc(var(--content-size) * 0.68);font-weight:700;color:var(--screen-fg);line-height:1.3;text-align:left;overflow:hidden;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;}
.yc-title-sub{font-weight:400;}
/* Rosh Chodesh — the new month's Hebrew name, large and centered */
.yc-rc-center{flex:1 1 auto;min-height:0;display:flex;align-items:center;justify-content:center;font-family:var(--font-hebrew);direction:rtl;font-weight:700;font-size:calc(var(--content-size) * 1.15);color:var(--screen-fg);line-height:1;overflow:hidden;}
.yc-t-heb{font-family:var(--font-hebrew);direction:rtl;font-weight:700;}
/* Fast — inline Begins / Ends rows (the day cell is already the box) */
.yc-fast{display:flex;flex-direction:column;gap:0.08cqi;}
.yc-fast-row{display:flex;justify-content:space-between;gap:0.4cqi;font-size:calc(var(--content-size) * 0.68);color:var(--screen-fg);line-height:1.15;white-space:nowrap;text-align:left;}
/* Candle / havdalah times — pinned to the cell bottom */
.yc-times{display:flex;flex-direction:column;gap:0.15cqi;flex-shrink:0;margin-top:0.35cqi;}
.yc-times:empty{display:none;}
.yc-candle{display:flex;justify-content:space-between;gap:0.4cqi;width:100%;font-size:calc(var(--content-size) * 0.68);color:var(--screen-fg);line-height:1.15;white-space:nowrap;text-align:left;}
/* Day states */
.yc-day.trailing .yc-gd{color:rgba(0,0,0,0.4);}
.yc-day.trailing .yc-hd{color:rgba(0,0,0,0.4);}
.yc-day.trailing .yc-cell-body,.yc-day.trailing .yc-times,.yc-day.trailing .yc-rc-center{opacity:0.4;}
/* .today/.sel carry no visual marker — today reads from its TODAY chip
   alone (live view only; captures blank the chip in the capture block
   below), and the classes stay on the cells for focus restore. */
/* DOW abbreviation is hidden by default (landscape/device show the full
   day names); the portrait block below flips this. */
.yc-dow-hdr .dow-abbr{display:none;}

/* ================================================================
   14b · MONTH CALENDAR — PORTRAIT (phone) overrides
   The landscape/device calendar is a fixed-aspect card, so the
   absolute overlay always has a definite height and the 7 wide cells
   hold full-length text. Portrait is different on both counts, so
   everything here is scoped to .orient-portrait and never touches the
   landscape/device month layout.
   ================================================================ */
/* HEIGHT — the portrait .screen is content-sized (aspect-ratio:auto).
   openYearCal() hides the dashboard's in-flow children (.tb/.body), so
   with nothing left in flow the screen — and the absolute overlay's
   inset:0 — collapse to zero height. Pin a viewport-based height while
   the calendar is open so the grid actually fills the phone. */
.screen.orient-portrait:has(> #yc-overlay:not([hidden])){min-height:calc(100svh - 140px);}
/* (Overlay stacking above the dashboard topbar is handled globally on
   .yc-overlay — z-index:20 — since the same render()-while-open race
   applies in both orientations.) */
/* HEADER — give the month header clearance from the phone status bar /
   notch. env() only resolves with viewport-fit=cover; the 2% base
   keeps a sensible gap regardless. Height goes auto so the px-sized
   buttons below set the bar's height instead of the % topbar-height. */
.screen.orient-portrait .yc-topbar{margin-top:max(2%, env(safe-area-inset-top, 0px));height:auto;min-height:var(--topbar-height);padding:5px 10px;}
/* HEADER BUTTONS — the shared cqi sizes (6.6cqi TODAY, 3cqi arrows)
   collapse to ~25px / ~11px against a phone-width container, clipping
   "TODAY" and shrinking the arrows below a tap target. Pin them in px
   for portrait. */
.screen.orient-portrait .yc-btn{height:auto;min-height:26px;padding:3px 10px;font-size:11px;letter-spacing:0.3px;}
/* Phone header balance (Joseph, 2026-07-23: TODAY removed — the app
   bar above already has Today): side groups size to content, the
   center spreads ◀ · title · ▶ across the rest. The title stack's
   fixed landscape width (--topbar-parsha-size × 7) overflowed its
   grid track on a phone and shoved ▶ into JUMP — let it size to the
   text instead, and keep real breathing room before the JUMP pill. */
.screen.orient-portrait .yc-tb-left,
.screen.orient-portrait .yc-tb-right{flex:0 0 auto;}
/* Arrows HUG the title (Joseph, 2026-07-23): the center group packs
   ◀ · title · ▶ around a FIXED-width title box and centers the trio,
   instead of pushing the arrows to the bar's far edges. The box is
   sized once for the widest title the calendar can produce — measured
   38cqi covers "September 2026" over "אלול - תשרי 5786 - 5787" (the
   two-year Elul/Tishrei span; the leap-year double-Adar pair is
   narrower) — so the arrows sit at the same spot every month. */
.screen.orient-portrait .yc-tb-center{flex:1;min-width:0;gap:10px;grid-template-columns:auto auto auto;justify-content:center;}
.screen.orient-portrait .yc-title-stack{width:38cqi;max-width:100%;min-width:0;overflow:hidden;}
.screen.orient-portrait .yc-tb-right{margin-left:8px;}
/* The landscape #yc-jump pin (6.6cqi ≈ 25px on a phone, padding:0)
   out-specifies the portrait .yc-btn sizing and the JUMP text spilled
   over its pill onto the ▶ arrow — size the pill to its label. */
.screen.orient-portrait #yc-jump{width:auto;padding:3px 12px;}
.screen.orient-portrait .yc-btn-ico{width:26px;min-width:26px;height:26px;padding:0;}
.screen.orient-portrait .yc-btn-ico svg{width:11px;height:11px;}
/* DOW — swap full names for 3-letter abbreviations so 7 columns fit. */
.screen.orient-portrait .yc-dow-hdr{letter-spacing:0.04cqi;}
.screen.orient-portrait .yc-dow-hdr .dow-full{display:none;}
.screen.orient-portrait .yc-dow-hdr .dow-abbr{display:inline;}
/* DAY NUMBERS — the Gregorian number + Hebrew gematria share the top
   row; at the landscape 1.28× size they collide / overflow a ~46px
   cell (the Saturday column especially). Trim to ~1.02× and clip. */
.screen.orient-portrait .yc-gd,
.screen.orient-portrait .yc-hd{font-size:calc(var(--content-size) * 1.02);}
.screen.orient-portrait .yc-day-top{gap:0.2cqi;overflow:hidden;}
.screen.orient-portrait .yc-day-top .yc-gd,
.screen.orient-portrait .yc-day-top .yc-hd{min-width:0;overflow:hidden;}
/* The "TODAY" word crowds the day numbers out of a ~46px cell; the
   2px black ring on the cell already marks today, so drop the word in
   portrait and keep the Gregorian + Hebrew numbers legible. */
.screen.orient-portrait .yc-today-lbl{display:none;}
/* CELL TEXT — cells are ~1/7 of a phone width (~46px inner), far
   narrower than landscape. Let event text wrap instead of hard-
   truncating, and shrink the event tier a touch so more fits. */
.screen.orient-portrait .yc-parsha,
.screen.orient-portrait .yc-title,
.screen.orient-portrait .yc-candle,
.screen.orient-portrait .yc-fast-row{font-size:calc(var(--content-size) * 0.6);}
.screen.orient-portrait .yc-parsha{white-space:normal;overflow-wrap:anywhere;text-overflow:clip;line-height:1.08;}
/* TIMES — stack the label above its time so neither shares a cramped
   46px line. The label may wrap; the time stays on one line so it can
   never clip mid-number ("Begins 4:1" → "Begins" / "4:17"). */
.screen.orient-portrait .yc-fast-row,
.screen.orient-portrait .yc-candle{flex-direction:column;align-items:flex-start;gap:0;line-height:1.08;}
.screen.orient-portrait .yc-fast-row > span:first-child,
.screen.orient-portrait .yc-candle > span:first-child{white-space:normal;}
.screen.orient-portrait .yc-fast-row > span:last-child,
.screen.orient-portrait .yc-candle > span:last-child{white-space:nowrap;font-weight:700;}

/* ── Full-screen Jump-to-date picker ───────────────────────────────── */
.jf-overlay{position:absolute;inset:0;z-index:30;display:flex;flex-direction:column;background:var(--screen-bg);color:var(--screen-fg);font-family:var(--font-body);}
.jf-overlay[hidden]{display:none;}
/* Bottom inset is 2cqi — the SAME breath the footer buttons keep from
   each other and (near enough) from the side walls, so the
   Cancel / Go / Saved Dates row floats off the screen bottom instead
   of hugging it (Joseph's ruling). */
.jf-inner{width:100%;height:100%;display:flex;flex-direction:column;padding:0 var(--right-padding) 2cqi var(--left-padding);box-sizing:border-box;gap:1.6%;}
.jf-top{position:relative;flex-shrink:0;margin-top:0.9%;background:transparent;border-radius:var(--tb-radius,26px);height:7.0875cqi;display:flex;align-items:center;justify-content:space-between;padding:0 8px;}
.jf-tb-side{display:flex;align-items:center;flex:1;min-width:0;}
.jf-tb-end{justify-content:flex-end;}
.jf-title{position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);font-weight:800;font-size:calc(var(--content-size) * 1.21);letter-spacing:0.01em;color:var(--topbar-fg);white-space:nowrap;}
/* SAVED DATES rows: bold name + muted kind left, bold dates right. */
/* the list spans the jf-body's full width as BALANCED newspaper
   columns - at least 3, one more per further 20 dates (--sd-cols set
   by openSavedDates), so however many dates exist, they fit */
.sd-list{grid-column:1 / -1;display:block;column-count:var(--sd-cols,3);column-gap:3cqi;padding:0 0.5cqi;height:100%;overflow:hidden;min-height:0;}
.sd-row{break-inside:avoid;}
/* NO scrolling, and NOTHING truncated: a standard row is 5% of the
   body (20 lines per column); a long entry wraps to a second line and
   simply costs its column a slot. openSavedDates measures the result
   and adds columns only once the page is genuinely full, then pads
   the leftover space with empty ruled lines. */
/* Rows follow the zmanim/shabbos/upcoming ledger's anatomy (regular
   label, bold value) at 85% of the body tier — Joseph sized it down
   from the full --content-size on review. */
.sd-row{display:grid;grid-template-columns:minmax(0,1fr) auto;column-gap:1.2cqi;align-items:center;min-height:5%;box-sizing:border-box;padding:0.25cqi 0.3cqi;border-bottom:2px dotted #b9b9b9;font-size:calc(var(--content-size) * 0.85);break-inside:avoid;}
.sd-row-empty{min-height:0;height:5%;}
/* Left cell is ordinary inline flow: the browser breaks between the
   name and the kind when that fits, or inside a long name at a word
   boundary when it must - and nothing ever overflows its box. */
.sd-l{min-width:0;line-height:1.2;display:block;}
.sd-row:last-child{border-bottom:none;}
/* Bottom row of EACH column (marked by openSavedDates): no dotted
   rule — nothing sits beneath it. */
.sd-row.sd-col-last{border-bottom:none;}
/* The row is typographically IDENTICAL to a zmanim row: name reads
   like a .zl label (400 at --content-size), the date like a .zt value
   (700). The bold-on-both look made the rows read oversized even at
   the same font-size. */
.sd-name{font-weight:400;}
.sd-kind{color:#777;font-weight:600;font-size:calc(var(--content-size) * 0.68);} /* 0.8 de-emphasis ratio against the 0.85 row */
/* The date column sizes between its dot-break (min) and one line
   (max) - splitting to "Nov 21 ·" / "20 Cheshvan" only when tight. */
.sd-date{font-weight:700;white-space:normal;text-align:right;line-height:1.2;}
.sd-empty{color:#666;font-style:italic;padding:1cqi 0.3cqi;font-size:calc(var(--content-size) * 0.85);}
.jf-body{flex:1;min-height:0;overflow:hidden;display:grid;grid-template-columns:repeat(3,1fr);gap:2cqi;align-items:stretch;}
/* Jump picker lays out on ONE shared grid: row 1 the three category
   pills, row 2 the full-width year bar, rows 3-4 the month/day grids
   (Holiday's list spans both). Rows pack at the top (align-content),
   and the 2cqi row-gap equals the column gap so every section is
   separated by the same breath. The panels become display:contents so
   their children sit directly on the shared grid; portrait re-blocks
   them for the stacked one-column flow. */
/* Vertical rhythm (per Joseph's mockup): the three category labels
   anchor to the TOP (row 1), the selection block — year bar + months
   + days — floats CENTERED in the leftover height (equal 1fr spacer
   rows 2 and 6), and the footer stays pinned to the bottom of
   .jf-inner as before. */
#jf-overlay .jf-body{grid-template-rows:auto minmax(0,1fr) auto auto auto minmax(0,1fr);}
.jf-panel{display:contents;}
.jf-panel[data-panel="eng"]>*{grid-column:1;}
.jf-panel[data-panel="heb"]>*{grid-column:2;}
.jf-panel[data-panel="hol"]>*{grid-column:3;}
.jf-phead{grid-row:1;}
/* Category pill text matches the chips below it (same weight, same
   size) — the pill shape and the inverted active fill do the talking. */
.jf-plabel{display:flex;align-items:center;justify-content:center;width:100%;height:3.4cqi;box-sizing:border-box;text-align:center;font-weight:600;font-size:calc(var(--content-size) * 0.74);border:1.5px solid #000;border-radius:0.9cqi;padding:0 1.2cqi;line-height:1.1;cursor:pointer;}
.jf-plabel:hover{background:#f1f1f1;}
.jf-panel.is-active .jf-plabel:hover{background:var(--screen-fg);}
.jf-panel.is-active .jf-plabel{background:var(--screen-fg);color:var(--screen-bg);}
.jf-grid{display:grid;gap:0.7cqi;flex-shrink:0;align-self:start;align-content:start;}
.jf-g-mon{grid-template-columns:repeat(3,1fr);grid-row:4;}
/* Hebrew has 14 month chips (both Adars) — four per line keeps its
   month block the same height as the English one. */
.jf-panel[data-panel="heb"] .jf-g-mon{grid-template-columns:repeat(4,1fr);}
.jf-g-day{grid-template-columns:repeat(7,1fr);grid-row:5;}
.jf-g-hol{grid-template-columns:repeat(2,1fr);grid-row:4 / span 2;}
.jf-chip{background:#fff;border:1.5px solid #000;color:var(--screen-fg);font-family:var(--font-body);font-weight:600;font-size:calc(var(--content-size) * 0.74);padding:0 0.3cqi;border-radius:0.9cqi;cursor:pointer;text-align:center;line-height:1.1;height:3.4cqi;display:flex;align-items:center;justify-content:center;}
.jf-chip:hover{background:#f1f1f1;}
.jf-chip.is-sel{background:var(--screen-fg);color:var(--screen-bg);border-color:var(--screen-fg);font-weight:800;}
.jf-g-hol .jf-chip{padding-inline:0.9cqi;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}
.jf-yearbar{flex-shrink:0;display:grid;grid-template-columns:repeat(4,1fr);gap:0.9cqi;grid-column:1/-1;grid-row:3;}
.jf-yearbar .jf-chip{font-variant-numeric:tabular-nums;font-weight:700;}
.jf-err{flex-shrink:0;color:var(--screen-fg);font-size:calc(var(--content-size) * 0.72);font-weight:600;text-align:center;}
.jf-err[hidden]{display:none;}
/* Footer shares the page's 2cqi gutter; the primary action owns the
   center: Cancel 1/6, Go 4/6, Saved Dates 1/6. */
.jf-ftr{display:grid;grid-template-columns:1fr 4fr 1fr;gap:2cqi;flex-shrink:0;}
.screen.orient-portrait .jf-ftr{display:flex;gap:1.2cqi;}
/* Footer actions wear the same clothes as the chips above them (same
   height, radius, stroke, and text voice as the year bar) so the row
   reads as part of the page, not separate furniture. */
.jf-btn{flex:1;background:#fff;border:1.5px solid #000;color:var(--screen-fg);font-family:var(--font-body);font-weight:600;font-size:calc(var(--content-size) * 0.74);padding:0 0.5cqi;height:3.4cqi;display:flex;align-items:center;justify-content:center;border-radius:0.9cqi;cursor:pointer;}
.jf-btn:hover{background:#f1f1f1;}
/* Saved Dates hugs its text; Cancel and Go share the freed width. */
#jf-saved{flex:0 0 auto;padding-left:2.2cqi;padding-right:2.2cqi;}
/* Back matches the shared pill spec (battery / Today / Jump): same
   6.6 x 3 cqi box, centered text. */
#sd-back,#jf-today{width:6.6cqi;padding:0;box-sizing:border-box;}
.jf-go{background:var(--screen-fg);color:var(--screen-bg);border-color:var(--screen-fg);flex:2;}
.jf-go:hover{background:#000;}
/* Portrait phones: stack into one scrolling column. */
.screen.orient-portrait .jf-body{grid-template-columns:1fr;gap:0;overflow-y:auto;display:block;}
.screen.orient-portrait .jf-panel{display:block;border-top:1px solid rgba(0,0,0,0.14);padding-top:1.4cqi;margin-top:1.4cqi;}
.screen.orient-portrait .jf-panel:first-child{border-top:0;padding-top:0;margin-top:0;}
.screen.orient-portrait .jf-g-mon{grid-template-columns:repeat(4,1fr);}
.screen.orient-portrait .jf-g-mon,.screen.orient-portrait .jf-g-hol{grid-auto-rows:auto;margin-top:0.9cqi;}
.screen.orient-portrait .jf-g-day{grid-auto-rows:auto;margin-bottom:0;}
.screen.orient-portrait .jf-title{font-size:21px;}
.screen.orient-portrait .jf-plabel{font-size:14px;height:auto;min-height:40px;padding:0 12px;}
.screen.orient-portrait .jf-chip{font-size:14px;height:auto;min-height:40px;padding:8px 2px;border-radius:9px;}
.screen.orient-portrait .jf-yearbar{margin-top:1.4cqi;}
.screen.orient-portrait #jf-today,.screen.orient-portrait #sd-back{height:32px;padding:0 16px;border-radius:16px;font-size:13px;}
.screen.orient-portrait .sd-list{column-count:1;}
.screen.orient-portrait .sd-row-empty{display:none;}
.screen.orient-portrait .sd-list{height:auto;overflow-y:auto;}
.screen.orient-portrait .sd-row{font-size:15px;padding:9px 2px;height:auto;}
.screen.orient-portrait .sd-kind{font-size:12px;}
.screen.orient-portrait .jf-btn{font-size:14px;padding:11px 4px;border-radius:10px;}
.screen.orient-portrait #jf-saved{flex:0 0 auto;padding:11px 14px;}

/* ── Account integration: welcome step + nav ───────────────────────── */
.zip-welcome,.zip-form{display:flex;flex-direction:column;align-items:center;gap:14px;}
.zip-signin{text-decoration:none;text-align:center;display:block;}
#nav-account{text-decoration:none;}
