/* app-rail.css: the one menu's styling, on every page.
 *
 * This lives in its own file, linked from all 63 pages, for one concrete reason:
 * the site's pages split between app.css and learn/learn.css, so NO stylesheet on
 * disk reaches all of them. native-api.js hit the same wall and solved it with an
 * injected <style> node, which it could do because the shells serve local files
 * with no CSP header. The web has one (worker.js: style-src 'self' 'unsafe-inline'),
 * and a real stylesheet is cacheable and reviewable besides, so the web takes the
 * <link> route instead.
 *
 * Found the hard way: the first build of this put the rules in app.css, and the
 * rail duly appeared on /calculators and /learn as an unstyled block of links at
 * the bottom of the document. The menu that exists to make those pages feel like
 * the app was the thing that looked broken on them.
 *
 * Every rule is scoped to .has-rail, which app-rail.js sets and the markup never
 * does: if the script fails, the site-nav must still be there to navigate with.
 *
 * Colours are Carolyn's four and no fifth (section 16), with literal fallbacks
 * because learn.css does not define the same custom properties app.css does.
 */
/* ---------- THE APP RAIL (dev build, 2026-08-14) ----------
   The web half of the one-menu redesign (docs/decisions/live-board-menu-redesign.md).
   Bottom bar on phones and laptops, right rail on a wide desktop, one element either
   way: app.js mounts #tbrail once and this file decides its orientation.

   Colours are Carolyn's four and no fifth (section 16): ink ground, chalk for the
   resting label, cream for the active one, and the pen only as the small active
   mark, which is the composition's one red object. Identical values to the native
   bar in native-api.js, so the two platforms read as the same product.

   .has-rail is set by app.js, never in the markup: if the script does not run there
   is no rail, and the site-nav and tablist must stay visible rather than leaving a
   reader with no navigation at all. That is why every hiding rule below is scoped
   to .has-rail. */
#tbrail { position: fixed; z-index: 340; background: var(--ink, #17171A);
  display: flex; font-family: Karla, sans-serif; }
#tbrail .tbrail-i { display: flex; align-items: center; color: #9C978E;
  text-decoration: none; font-size: 12.5px; letter-spacing: .04em; position: relative; }
#tbrail .tbrail-i svg { width: 23px; height: 23px; flex: none; }
#tbrail .tbrail-i.is-here { color: #F4EFE3; }
#tbrail .tbrail-i:hover { color: #F4EFE3; }

/* BOTTOM BAR, up to 1279px. Same idiom as the store shells. */
/* BOTTOM BAR, up to 1279px. Owner, 2026-08-14: "I want the rail to appear on mobile
   the way it does on the iOS app, at the bottom." So these are not approximations of
   the shell's bar, they are ITS OWN NUMBERS, lifted from native-api.js's injected
   sheet: 4px 0 2px padding, 11px labels, 23px icons, a 3px gap, items capped at
   220px so an iPad does not fling six tabs to the far corners, and the active mark
   3px tall at top:-7px. If one file's values change the other should change with it,
   or the same product reads differently on two screens the same person owns. */
@media (max-width: 1279px) {
  #tbrail { left: 0; right: 0; bottom: 0; border-top: 1px solid var(--rule, #2a2a2f);
    padding-bottom: env(safe-area-inset-bottom, 0px); justify-content: center; }
  #tbrail .tbrail-i { flex: 1; max-width: 220px; flex-direction: column; gap: 3px;
    padding: 4px 0 2px; justify-content: center; text-align: center;
    font-size: 11px; letter-spacing: .04em; }
  /* six tabs on a 390px phone give each ~65px, and "Report Card" is the one label
     that wraps at 11px. It is allowed to take two lines rather than being renamed
     or truncated: the shells show the same words, and a tab that says "Report" on
     the web and "Report Card" in the app is two products. */
  #tbrail .tbrail-i span { line-height: 1.15; }
  #tbrail .tbrail-i.is-here::after { content: ""; position: absolute; top: -7px;
    left: 50%; transform: translateX(-50%); width: 22px; height: 3px;
    border-radius: 2px; background: var(--pen, #D3342C); }
  /* the bar is fixed, so the last game card needs somewhere to end */
  html.has-rail body { padding-bottom: calc(64px + env(safe-area-inset-bottom, 0px)); }
}

/* RIGHT RAIL, 1280px and up. main caps at 1020px, so 1280 - 240 = 1040 still clears
   it: the rail costs ZERO board columns at its own breakpoint, which is the measured
   claim the redesign turns on. body gets the padding rather than main so the header
   and footer shift with it and nothing sits under the rail. */
@media (min-width: 1280px) {
  #tbrail { top: 0; bottom: 0; left: 0; width: 240px; flex-direction: column;
    gap: 2px; padding: 22px 12px; border-right: 1px solid var(--rule, #2a2a2f); }
  #tbrail .tbrail-i { gap: 12px; padding: 11px 14px; border-radius: 10px;
    font-size: 14.5px; }
  #tbrail .tbrail-i:hover { background: rgba(244, 239, 227, .06); }
  #tbrail .tbrail-i.is-here { background: rgba(244, 239, 227, .09); }
  /* vertical mark on the leading edge, the rail's answer to the bar's underline */
  #tbrail .tbrail-i.is-here::before { content: ""; position: absolute; left: 0;
    top: 50%; transform: translateY(-50%); width: 3px; height: 20px;
    border-radius: 2px; background: var(--pen, #D3342C); }
  html.has-rail body { padding-left: 240px; }
}

/* THE TWO BARS THE RAIL REPLACES. Hidden, never removed: the markup stays in
   app.html so the 63 inbound nav links and nav.test.js's four-anchor assertion are
   both untouched, and a reader with JS off still gets a working site-nav. */
html.has-rail .site-nav { display: none; }

/* Nothing paints over the 21+ gate, the same invariant the native bar now obeys.
   Belt to the z-index braces: .agegate sits at 400 and this rail at 340, so the
   gate already wins, and this makes the intent explicit and drops the rail out of
   the tab order while the gate is open. */
html:has(#agegate:not([hidden])) #tbrail { display: none; }

/* ---------- THE BRAND IN THE RAIL (owner, 2026-08-15) ----------
   Desktop: mark plus wordmark at the head of the left rail. Phone: the mark alone,
   hard against the left edge, and NOT a tab: flex:0 so it never takes a sixth of the
   bar away from the six destinations that have somewhere to go. */
#tbrail .tbrail-brand { display: flex; align-items: center; text-decoration: none;
  color: var(--cream, #F4EFE3); }
#tbrail .tbrail-mark { width: 26px; height: 26px; flex: none; border-radius: 6px; }
#tbrail .tbrail-word { font-family: Montserrat, sans-serif; font-weight: 800;
  letter-spacing: -0.02em; font-size: 16px; }

@media (max-width: 1279px) {
  /* icon only, pinned left, and it does not compete with the tabs for width */
  #tbrail { justify-content: flex-start; padding-left: 10px; }
  #tbrail .tbrail-brand { flex: none; padding: 0 12px 0 2px; }
  #tbrail .tbrail-word { display: none; }
  /* the tabs still share what is left, centred among themselves */
  #tbrail .tbrail-i { flex: 1 1 0; }
  /* PRICING COMES OFF THE PHONE BAR (owner, 2026-08-15: "lets pull pricing off the
     rail on mobile, its getting a little crowded"). Six destinations plus the mark
     on a 390px bar gives each about 60px, and Pricing is the one a reader visits
     once rather than moves between. It stays on the desktop rail, in the footer of
     all 64 pages and in the account menu's upgrade row, so no route to the page
     that takes money is lost: it just stops spending a sixth of the bar. */
  #tbrail .tbrail-i[href="/pricing"] { display: none; }
}

@media (min-width: 1280px) {
  #tbrail .tbrail-brand { gap: 10px; padding: 4px 14px 18px; }
  #tbrail .tbrail-mark { width: 30px; height: 30px; }
}
