/* ==========================================================================
   The Next Coin Club — responsive.css
   Fit, reach and rhythm across every real device. Loads LAST.

   WHY THIS FILE EXISTS
   --------------------
   The platform's responsive behaviour was written breakpoint-by-breakpoint,
   page-by-page, as each page was built. The result is ten uncoordinated
   thresholds — 560, 640, 700, 760, 820, 860, 899, 900, 920, 960 — that fire
   in an order nobody designed. Between 700px and 760px, for example,
   learn.html has collapsed its `.grid2` but company.html has not collapsed
   its `.two`; at 899px the member sidebar disappears but lesson.html keeps
   its 210px table of contents until 960px, so for 61px of viewport the
   lesson page has no primary navigation AND a secondary one.

   This file does not delete those rules — they are in files owned by other
   people. It layers a coherent system over them, keyed to real hardware:

     320   iPhone SE (1st gen), the true floor
     360   Galaxy S-series, the most common Android width on earth
     390   iPhone 12/13/14/15
     414   iPhone Plus / Pro Max
     768   iPad portrait
     834   iPad Air / Pro 11" portrait
     1024  iPad landscape, small laptop
     1280  the common laptop
     1440  MacBook Pro 15/16"
     1920  desktop standard
     2560  27" 1440p and up

   SPECIFICITY NOTE
   ----------------
   Page-local <style> blocks currently load AFTER the stylesheet <link>s, so
   a bare `.grid2` here would lose to a page's `.grid2`. Two defences are
   used: this file is specified to load last (see states.css §14), and where
   it must override a known page-local rule it qualifies the selector with
   `body` to take the specificity. `!important` is used only where a page
   sets an inline style attribute, which cannot be beaten any other way —
   each instance is commented.

   CONTENTS
   --------
   §1   Global guards (overflow, text scaling, dynamic viewport)
   §2   Safe-area insets
   §3   Tap-target minimums
   §4   The member shell: sidebar <-> tab bar
   §5   Tab bar vs content overlap
   §6   Wide rows and tabular content on narrow screens
   §7   The lesson two-column layout
   §8   Hero and display-type scaling at the extremes
   §9   Phone tier: 320 / 360 / 390 / 414
   §10  Tablet tier: 768 / 834 / 1024
   §11  Desktop tier: 1280 / 1440 / 1920 / 2560
   §12  Landscape phone
   §13  Print (legal, standards, security, terms, privacy)
   ========================================================================== */


/* ==========================================================================
   §1  GLOBAL GUARDS
   ========================================================================== */

/* Nothing may cause a horizontal scrollbar. `overflow-x:hidden` on <html>
   as well as <body> is required — on iOS Safari, body alone does not hold. */
html,body{max-width:100%;overflow-x:hidden}

/* Long unbroken strings — wallet addresses, transaction hashes, referral
   URLs, email addresses — are the single most common cause of horizontal
   overflow in a crypto product, and this platform will display all four.
   invite.html renders a referral link; profile.html will render a handle;
   any of them at 320px will push the layout wider than the screen. */
p,li,td,dd,figcaption,
.lede,.srow p,.row .ti,.mod p,.th p,.lrow .t,.lrow .s,
.ncc-toast-msg,.ncc-alert-msg{
  overflow-wrap:break-word;
  word-break:normal;                  /* never break ordinary words */
}
/* Elements that will hold a genuinely unbreakable token get the stronger
   rule. `anywhere` is correct here and wrong above: it will break a normal
   word mid-syllable if it has to. */
code,kbd,samp,.ncc-error-detail pre,
[data-breakable],.ncc-copyable{overflow-wrap:anywhere}

/* iOS zooms the page when a focused input is under 16px. app.css sets 16px
   on text inputs correctly, but three controls escape it: community.html's
   composer textarea (15px inline), settings.html's injected `.js-field`
   (14px inline) and any <select>. All three are fixed here. The inline
   styles on those two elements can only be beaten with !important. */
input,textarea,select,button{font-family:inherit}
@media(max-width:899px){
  textarea,
  select,
  input[type=text],input[type=email],input[type=password],
  input[type=tel],input[type=number],input[type=search],
  textarea#pt,                        /* community.html composer   */
  .js-field{                          /* settings.html inline edit */
    font-size:16px !important;        /* inline style override */
  }
}

/* Use the dynamic viewport unit where a full-height box is intended, so the
   collapsing mobile browser chrome does not clip the bottom of a panel. */
@supports(height:100dvh){
  .ncc-modal{height:100dvh}
}

/* Respect the user's own text-size preference: cap our clamps against a
   rem-based ceiling so a 200% browser zoom still scales display type. */
.d1,.d2,.d3{max-width:100%}


/* ==========================================================================
   §2  SAFE-AREA INSETS
   --------------------------------------------------------------------------
   The platform uses `env(safe-area-inset-*)` in exactly zero places. On
   every notched or gesture-bar iPhone (X onward — the majority of the
   platform's likely audience) this means:

     - The member tab bar's labels sit UNDER the home indicator.
     - The sticky bottom bar on marketing pages does the same.
     - In landscape, the nav logo and the theme switch sit under the notch.

   `viewport-fit=cover` must be added to each page's viewport meta for these
   to take effect — that is an HTML change, documented in UX_AUDIT.md. These
   rules are written so they are harmless before that change lands (env()
   resolves to 0px) and correct after it.
   ========================================================================== */

:root{
  --sa-t:env(safe-area-inset-top,0px);
  --sa-r:env(safe-area-inset-right,0px);
  --sa-b:env(safe-area-inset-bottom,0px);
  --sa-l:env(safe-area-inset-left,0px);
}

/* Member tab bar — the critical one. Padding, not margin: the frosted
   background must extend behind the home indicator, only the touchable
   content moves up. */
body .tabs{
  padding-bottom:calc(13px + var(--sa-b));
  padding-left:calc(6px + var(--sa-l));
  padding-right:calc(6px + var(--sa-r));
}

/* Marketing sticky bar */
body .stickybar{
  padding-bottom:calc(11px + var(--sa-b));
  padding-left:calc(16px + var(--sa-l));
  padding-right:calc(16px + var(--sa-r));
}

/* Nav and footer in landscape, where left/right insets are non-zero. */
body .navin{
  padding-left:calc(24px + var(--sa-l));
  padding-right:calc(24px + var(--sa-r));
}
body footer{
  padding-left:calc(24px + var(--sa-l));
  padding-right:calc(24px + var(--sa-r));
}
body .wrap{
  padding-left:calc(24px + var(--sa-l));
  padding-right:calc(24px + var(--sa-r));
}
body .appshell{
  padding-left:calc(22px + var(--sa-l));
  padding-right:calc(22px + var(--sa-r));
}
/* The command palette, which is full-screen fixed. */
body .cmdk{
  padding-left:calc(20px + var(--sa-l));
  padding-right:calc(20px + var(--sa-r));
  padding-bottom:calc(20px + var(--sa-b));
}


/* ==========================================================================
   §3  TAP-TARGET MINIMUMS
   --------------------------------------------------------------------------
   WCAG 2.2 SC 2.5.8 asks for 24x24 CSS px; Apple and Google both ask for
   44x44 and 48x48 respectively. 44px is the target here.

   Measured failures on the platform today (height, at rest):

     .tabs a           ~40px   primary member navigation
     .seg button       ~26px   theme switch, on every page
     .kbd              ~30px   search trigger
     .sw               26px    every settings toggle
     .filt button      ~39px   community filters
     .btn              ~38px   the standard button, everywhere
     .fgrid a          ~30px   every footer link
     .toc a            ~32px   lesson contents
     .ghost            ~35px
     .side a           ~40px   member sidebar
     .navlinks a       ~22px   (desktop only, pointer:fine — acceptable)

   The technique below adds hit area WITHOUT changing visual size, using a
   pseudo-element overlay. This matters: inflating these controls' padding
   would break the nav's 13px vertical rhythm and the tab bar's height, both
   of which other layout depends on.

   Scoped to `pointer:coarse` so mouse-driven desktop layouts are untouched.
   ========================================================================== */

@media(pointer:coarse){

  /* Shared hit-expander. The parent must be positioned; each rule below
     guarantees that. z-index keeps the expander under the element's own
     content but over its siblings' backgrounds. */
  .seg button,
  .kbd,
  .tabs a,
  .side a,
  .filt button,
  .toc a,
  .fgrid a,
  .ghost,
  .demo button,
  .reveal-pw,
  .lrow .go,
  .cmditem{
    position:relative;
  }
  .seg button::after,
  .kbd::after,
  .filt button::after,
  .toc a::after,
  .fgrid a::after,
  .ghost::after,
  .demo button::after,
  .reveal-pw::after{
    content:'';
    position:absolute;
    top:50%;left:50%;
    transform:translate(-50%,-50%);
    width:100%;height:100%;
    min-width:44px;min-height:44px;
    /* Sits behind the label so it never blocks text selection or the
       element's own ::before/::after decorations. */
    z-index:0;
  }
  /* .navlinks a already has an ::after (the underline). Expanding it would
     destroy that, so the link takes real padding instead — the desktop nav
     is hidden below 920px anyway, so this only affects large touch screens
     such as an iPad Pro in landscape. */
  .navlinks a{padding:11px 0}
  .navlinks{gap:20px}

  /* The theme switch. The segment is 26px tall by design and sits in a
     13px-padded nav; the expander above gives it 44px of reach without
     changing the nav's height. */
  .seg{position:relative}

  /* Settings toggles. The <label> is the hit area, so give the label the
     height rather than inflating the switch graphic. */
  .sw{min-height:44px;display:flex;align-items:center}
  .sw span{top:50%;transform:translateY(-50%);height:26px}

  /* Buttons. 44px minimum height, achieved with padding so the pill's
     radius still reads correctly. */
  .btn{min-height:44px;display:inline-flex;align-items:center;justify-content:center}
  .btn.full{display:flex}
  .btn.lg{min-height:50px}

  /* Tab bar. 56px is the platform convention for a bottom bar and gives the
     label room to sit under the icon without crowding. */
  .tabs a{min-height:52px;display:flex;flex-direction:column;
          align-items:center;justify-content:center}
  .tabs a .i{margin-bottom:2px}

  /* Sidebar links (visible on touch-capable large tablets). */
  .side a{min-height:44px}

  /* Lesson quiz options and community threads are already ≥44px; the
     lesson's per-row chevron is not, and is hover-only — see §6.4. */
}

/* Adjacent-target spacing. Two 44px targets touching each other still
   produce mis-taps; 8px of separation is the accepted minimum. */
@media(pointer:coarse){
  .cta{gap:12px}
  .acts{gap:12px}
  .filt{gap:10px}
  .lnav{gap:14px}
  .navright{gap:12px}
}


/* ==========================================================================
   §4  THE MEMBER SHELL — SIDEBAR <-> TAB BAR
   --------------------------------------------------------------------------
   app.css switches at 900px: `.side` appears, `.tabs` disappears. The switch
   itself is right, but the transition has three defects:

     1. At 900–1000px the 206px sidebar + 40px gap leaves a content column
        of ~700px inside the 1180px shell, while at 899px the content is the
        full width. The content column therefore JUMPS WIDER as the window
        narrows past 900px. That is backwards.
     2. iPad portrait (768/834) gets the phone tab bar, which is the correct
        call, but the content keeps the phone's single-column density on a
        1024px-tall screen — a lot of wasted horizontal space.
     3. There is no intermediate state. A 206px label-and-icon sidebar is
        affordable at 1100px; between 900 and 1100 an icon-only rail would
        serve better.

   §4 fixes 1 and 3. §10 addresses 2.
   ========================================================================== */

/* Narrow the sidebar and the gutter in the band where space is tight, so
   the content column grows monotonically with the viewport. */
@media(min-width:900px) and (max-width:1099px){
  body .appshell{
    grid-template-columns:64px 1fr;
    gap:24px;
  }
  /* Icon-only rail. Labels are hidden visually but stay in the accessibility
     tree — they are the link's accessible name. */
  body .side a{
    justify-content:center;
    padding:12px 0;
    gap:0;
    font-size:0;                       /* collapses the text node          */
    position:relative;
  }
  body .side a svg{font-size:14.5px}   /* restore for any em-based sizing  */
  body .side .sect{
    font-size:0;
    margin:16px 0 8px;
    padding-left:0;
    height:1px;
    background:var(--hair);
  }
  /* Tooltip on the rail, so an icon-only nav is still self-describing.
     Uses states.css §10 if the markup carries data-tip; this is the
     fallback for the current markup. */
  body .side a::after{
    content:attr(aria-label);
    position:absolute;left:calc(100% + 10px);top:50%;
    transform:translateY(-50%);
    background:var(--text);color:var(--bg);
    font-size:12px;padding:6px 9px;border-radius:8px;
    white-space:nowrap;opacity:0;pointer-events:none;
    transition:opacity var(--t-base);z-index:70;
  }
  body .side a:hover::after,
  body .side a:focus-visible::after{opacity:1}
}

/* Above 1100px the full sidebar returns, as designed. */
@media(min-width:1100px){
  body .appshell{grid-template-columns:206px 1fr;gap:40px}
}

/* The sidebar is `position:sticky; top:78px`, a hardcoded value that assumes
   the nav is at its un-condensed height. When the nav condenses (.stuck,
   8px padding) the sidebar's sticky offset is 12px too large, leaving a
   visible gap. Tie it to the actual condensed height. */
@media(min-width:900px){
  body .side{top:70px;max-height:calc(100dvh - 90px);overflow-y:auto;
             scrollbar-width:thin}
  /* A sidebar taller than the viewport must scroll independently rather
     than clipping its last item — Settings is the last item and the one
     people hunt for. */
  body .side::-webkit-scrollbar{width:6px}
}


/* ==========================================================================
   §5  TAB BAR vs CONTENT OVERLAP
   --------------------------------------------------------------------------
   The tab bar is `position:fixed` at the bottom, so it covers content unless
   the page reserves space. Today that reservation is made THREE different
   ways, and they disagree:

     app.css        `@media(max-width:899px){ body.member{padding-bottom:84px} }`
     dashboard.html `body{padding-bottom:88px}`   (inline <style>, all widths)
     lesson.html    `body{padding-bottom:88px}`   (same)
     community/live/launches/profile/invite/settings — the same 88px

   Consequences:
     - On DESKTOP (>=900px) the tab bar is hidden but the 88px padding
       remains, so every member page has a phantom 88px of dead space above
       the footer.
     - The 84px/88px values predate the FAB, which protrudes 24px above the
       bar (`.tabs .center .fab{top:-24px}`). The real occluded height is
       ~62px of bar + 24px of FAB overhang = 86px, plus the home-indicator
       inset, which nothing accounts for.

   The fix: one source of truth, expressed as a token, applied only where a
   tab bar actually exists.
   ========================================================================== */

:root{
  --tabbar-h:62px;                    /* measured height of .tabs */
  --fab-overhang:24px;                /* .tabs .center .fab top:-24px */
}

/* Reclaim the phantom space on desktop. `body[class]` outscores the pages'
   bare `body` selector without needing !important. */
@media(min-width:900px){
  body[class]{padding-bottom:0}
}

/* Reserve exactly the right amount on mobile, including the safe area. */
@media(max-width:899px){
  body[class].member{
    padding-bottom:calc(var(--tabbar-h) + var(--fab-overhang) + var(--sa-b));
  }
  /* The FAB overhangs the bar, so the last card in a page can slide under
     it. Give the shell's final child a little more clearance. */
  body.member .appshell > main > *:last-child{margin-bottom:8px}
}

/* dashboard.html's prototype view-toggle is `position:fixed; bottom:100px`
   and z-index 80 — it sits ON TOP of the tab bar's FAB on a 390px screen and
   covers the "Launches" affordance. Move it clear. This is a prototype
   control that should not ship at all (see UX_AUDIT.md), but while it does,
   it must not occlude navigation. */
@media(max-width:899px){
  body .viewtoggle{
    bottom:calc(var(--tabbar-h) + var(--fab-overhang) + 12px + var(--sa-b));
    right:12px;
  }
  body .viewtoggle .btn{font-size:12.5px;padding:8px 14px;min-height:40px}
}

/* Anchor targets must not land under the sticky nav. `scroll-margin-top` is
   set on lesson.html's h2 only; every in-page anchor on the platform needs
   it — standards.html#security, standards.html#risk, live.html#ask,
   index.html#learn, #live, #roadmap, #company all currently scroll to a
   position where their heading is hidden behind the nav. */
:target,
h1[id],h2[id],h3[id],section[id],div[id]{
  scroll-margin-top:88px;
}
@media(max-width:920px){
  :target,h1[id],h2[id],h3[id],section[id],div[id]{scroll-margin-top:74px}
}


/* ==========================================================================
   §6  WIDE ROWS AND TABULAR CONTENT ON NARROW SCREENS
   --------------------------------------------------------------------------
   The platform has no <table> elements, but it has six row components that
   behave like table rows and break the same way: a fixed-width first column,
   a flexible middle, and a right-aligned meta column that gets crushed.

     .row     (app.css)      .n is min-width:82px
     .srow    (app.css)      .k is min-width:32px
     .setrow  (settings)     label + control, no wrap rule
     .lrow    (learn)        num + chk + body + min + go
     .th      (community)    avatar + body + meta
     .frow    (press)        key/value pairs
     .pitem   (index)        the proof strip

   At 320px, `.row` gives its 82px index column 26% of the screen. At 360px,
   `.setrow`'s "Show in member directory" label and its 44px switch have
   ~250px between them, and the label wraps to three lines while the switch
   floats against the top. Both are fixed below.
   ========================================================================== */

/* --- 6.1 app.css rows ----------------------------------------------------- */
@media(max-width:520px){
  body .row{
    flex-wrap:wrap;
    gap:6px 14px;
    padding:15px 18px;
    align-items:flex-start;
  }
  /* The index becomes a label above the title rather than a column beside
     it, reclaiming 82px of a 320px screen. */
  body .row .n{min-width:0;width:100%;order:-1;font-size:11px}
  body .row .ti{flex:1 1 100%;font-size:15px}
  body .row .st{flex:0 0 auto}

  body .srow{padding:15px 18px;gap:12px}
  body .srow .k{min-width:26px}
}

/* --- 6.2 settings rows ---------------------------------------------------- */
@media(max-width:560px){
  body .setrow{
    flex-wrap:wrap;
    gap:12px;
    padding:16px 18px;
    align-items:center;
  }
  /* Text takes the full width; the control drops to its own line, aligned
     left with everything else rather than stranded on the right. */
  body .setrow .t{flex:1 1 100%;min-width:0}
  body .setrow .t span{display:block;margin-top:3px}
  body .setrow > .btn,
  body .setrow > a.btn{flex:0 0 auto}
  /* …except the switch, which is compact enough to stay inline and reads
     better beside its label. Keep it on the same row as the text by giving
     the text a floor width. */
  body .setrow:has(.sw) .t{flex:1 1 auto;min-width:60%}
  body .setrow .sw{margin-left:auto}
}

/* --- 6.3 press key/value rows --------------------------------------------- */
@media(max-width:560px){
  body .frow{flex-wrap:wrap;gap:4px 12px}
  body .frow .k{flex:1 1 100%}
}

/* --- 6.4 learn lesson rows ------------------------------------------------
   learn.html hides `.lrow .s` (the lesson description) entirely below 560px.
   That is content loss on the platform's core educational surface — the
   description is how a member decides whether to start the lesson. Restore
   it, clamped to two lines instead of removed. */
@media(max-width:560px){
  body .lrow .s{
    display:-webkit-box !important;    /* beats the page's `display:none`  */
    -webkit-line-clamp:2;
    -webkit-box-orient:vertical;
    overflow:hidden;
    font-size:12.5px;
  }
  body .lrow{gap:12px;padding:14px 16px}
  body .lrow .num{display:none}        /* the numbered chk already says it */
  body .lrow .min{font-size:11.5px}
}
/* `.lrow .go` is opacity:0 until :hover — on a touch device it is never
   visible, so the row loses its only "this is tappable" affordance. */
@media(hover:none){
  body .lrow .go{opacity:.55}
  body .th{position:relative}
}

/* --- 6.5 community threads ------------------------------------------------ */
@media(max-width:520px){
  body .th{gap:11px;padding:16px 16px}
  body .th .av2{width:30px;height:30px;font-size:11px}
  body .th .foot{gap:12px;flex-wrap:wrap;font-size:12px}
}

/* --- 6.6 index proof strip -----------------------------------------------
   `.pitem` uses `border-right` with `flex-wrap:wrap`. When the strip wraps,
   the last item of each ROW keeps its divider, leaving a rule hanging in
   space at the end of the line. Only `:last-child` is cleared. Below 640px
   index.html removes all borders — correct — but between 640 and 900 the
   ragged divider is visible. Clear it across the wrap range and give the
   items an even rhythm. */
@media(max-width:900px){
  body .proofin{gap:2px 0}
  body .pitem{padding:6px 18px}
}
@media(max-width:760px){
  body .pitem{border-right:0}
  body .proofin{gap:14px 0;padding:18px 20px}
  body .pitem{flex:1 1 40%}
}

/* --- 6.7 Any genuine table added later -----------------------------------
   A defensive rule so a future <table> cannot break the layout: it scrolls
   in its own box, with a shadow hinting there is more to the right. */
.ncc-table-scroll,
figure:has(> table){
  overflow-x:auto;
  overscroll-behavior-x:contain;
  -webkit-overflow-scrolling:touch;
  background:
    linear-gradient(to right,var(--bg) 30%,transparent) left/24px 100% no-repeat,
    linear-gradient(to left,var(--bg) 30%,transparent) right/24px 100% no-repeat,
    radial-gradient(farthest-side at 0 50%,var(--glow),transparent) left/10px 100% no-repeat,
    radial-gradient(farthest-side at 100% 50%,var(--glow),transparent) right/10px 100% no-repeat;
  background-attachment:local,local,scroll,scroll;
}
table{border-collapse:collapse;width:100%;font-size:14px}
th,td{padding:11px 14px;text-align:left;border-bottom:1px solid var(--hair)}
th{font-size:11.5px;letter-spacing:.14em;text-transform:uppercase;
   color:var(--dim);font-weight:600;white-space:nowrap}


/* ==========================================================================
   §7  THE LESSON TWO-COLUMN LAYOUT
   --------------------------------------------------------------------------
   lesson.html: `.lwrap{grid-template-columns:1fr 210px;gap:44px}` collapsing
   to one column at 960px, at which point `.toc` is `display:none`.

   Three problems:
     1. The collapse point (960) is above the shell's own (899), so between
        900 and 960 the page shows the member sidebar AND hides the table of
        contents — the reverse of what the space allows.
     2. Below 960 the table of contents is DELETED, not relocated. On a
        4-minute lesson with five headings, that is the only wayfinding the
        page has. A reader on a phone gets none.
     3. `.lbody p` is 17px/1.75 with `.lbody{max-width:660px}`. At 17px the
        660px measure is ~78 characters — above the 75ch comfortable ceiling,
        and noticeably hard to track back on a long lesson.

   Fixed: collapse in step with the shell, convert the TOC to a horizontal
   scroller rather than deleting it, and bring the measure to ~68ch.
   ========================================================================== */

/* 7.3 — the measure. 62ch at 17px ≈ 600px. */
body .lbody{max-width:64ch}
body .lbody p{text-wrap:pretty}

/* 7.1 — collapse in step with the shell, not 61px later. */
@media(min-width:900px) and (max-width:1099px){
  body .lwrap{grid-template-columns:1fr;gap:0}
}
@media(min-width:1100px){
  body .lwrap{grid-template-columns:1fr 210px;gap:44px}
  body .toc{display:block}
}

/* 7.2 — below the collapse, the contents become a sticky horizontal rail
   under the nav instead of disappearing. */
@media(max-width:1099px){
  body .toc{
    display:block;
    position:sticky;
    top:60px;
    z-index:40;
    border-left:0;
    border-bottom:1px solid var(--hair);
    padding:0 0 2px;
    margin:0 0 22px;
    background:color-mix(in srgb,var(--bg) 92%,transparent);
    backdrop-filter:blur(12px);
    -webkit-backdrop-filter:blur(12px);
    /* Bleed to the shell edges so the scroller reaches the screen edge —
       a rail that stops 22px short looks broken when it scrolls. */
    margin-left:calc(-22px - var(--sa-l));
    margin-right:calc(-22px - var(--sa-r));
    padding-left:calc(22px + var(--sa-l));
    padding-right:calc(22px + var(--sa-r));
  }
  /* The "Contents" label is redundant once it is a horizontal rail. */
  body .toc > div:first-child{display:none}
  body .toc{
    display:flex;
    gap:4px;
    overflow-x:auto;
    scrollbar-width:none;
    scroll-snap-type:x proximity;
  }
  body .toc::-webkit-scrollbar{display:none}
  body .toc a{
    flex:0 0 auto;
    padding:11px 12px;
    font-size:13px;
    white-space:nowrap;
    scroll-snap-align:start;
    border-bottom:2px solid transparent;
    min-height:44px;
    display:flex;align-items:center;
  }
  body .toc a.on{border-bottom-color:var(--text);color:var(--text)}
}

/* Lesson body type at the small end. 17px/1.75 is right for a 600px column
   and slightly loose for a 288px one; 16px/1.7 holds the same colour. */
@media(max-width:520px){
  body .lbody p{font-size:16px;line-height:1.7;margin-bottom:15px}
  body .pull{font-size:19px;padding-left:16px;margin:24px 0}
  body .lbody h2{margin:30px 0 12px}
}

/* The lesson's quiz options and prev/next nav. */
@media(max-width:520px){
  body .lnav{flex-direction:column}
  body .lnav .btn{width:100%}
  body .opt{padding:14px 14px;font-size:14px}
}

/* The reading-progress bar is `position:fixed; top:0` INSIDE `.appshell`,
   which is fine, but it renders above the sticky nav's own progress line.
   Keep it below the nav so the two do not double up. */
body .rprog{top:0;z-index:61}


/* ==========================================================================
   §8  HERO AND DISPLAY TYPE AT THE EXTREMES
   --------------------------------------------------------------------------
   The type scale is `clamp(min, vw, max)`, which is correct in the middle
   and wrong at both ends:

     .d1  clamp(40px, 6.6vw, 74px)
          At 320px: 6.6vw = 21px, so it clamps to the 40px floor. A 40px
          serif headline in a 272px content column gives ~7 characters per
          line. "The Next Coin Club" becomes four lines.
          At 2560px: clamps to 74px inside an 1100px column — correct.

     .d2  clamp(29px, 4.3vw, 50px)   — same floor problem at 320.
     --sect clamp(80px, 9.5vw, 136px)
          At 320px: 80px of vertical padding per section on a 568px-tall
          screen means a section header can be the only thing visible.

   The floors are tuned for 375px and are too tall below it. §9 lowers them
   per tier rather than changing the token, so nothing above 414px moves.
   ========================================================================== */

/* Balance long headlines rather than letting the last word orphan. Already
   set on h1–h4/.d1/.d2 in app.css; extend to the page-local display
   headings that were declared with raw font-family instead of .d1/.d2. */
body .greet h1,
body .phead h1,
body .box h1,
body .lesson h4,
body .pathhd h2,
body .hero-copy h2,
body .ncc-modal-title{text-wrap:balance}

/* Long real content in headings. "Week 3: what we finished, what broke" is
   already 36 characters in a card that is 1fr of a 2-column grid at 700px
   — 330px wide. Cap the measure so a longer real title wraps predictably
   instead of pushing the card's height past its sibling's. */
body .mod h3,
body .th h4,
body .fcard h3{max-width:30ch;text-wrap:balance}

/* Numbers that will break the layout at larger values. `.stat .big` is
   clamp(28px,4vw,38px) with tabular figures — "37%" is safe, "1,284,930"
   at 38px tabular is ~230px wide and sits in a flex row with a 96px ring
   inside a 22px-padded card. At 360px that is an overflow. */
body .stat .big{
  font-size:clamp(24px,4vw,38px);
  overflow-wrap:normal;
  max-width:100%;
}
@media(max-width:400px){
  body .stat .big{font-size:clamp(22px,7vw,30px)}
  /* The ring and the figure stop competing for a 300px row. */
  body .stat + .ring,
  body .surf > div > .ring{transform:scale(.85);transform-origin:right center}
}
/* Member numbers, counts and deltas must never wrap mid-number. */
body .stat .delta,
body .avstack .more,
body .badge,
body .greet .meta{white-space:nowrap}
@media(max-width:400px){
  body .greet .meta{white-space:normal}   /* "Member #147 · Joined today" */
}


/* ==========================================================================
   §9  PHONE TIER — 320 / 360 / 390 / 414
   ========================================================================== */

/* --- 414 and below: the shared phone baseline ----------------------------- */
@media(max-width:480px){
  /* Section rhythm. 80px floor -> 56px; the page still breathes but a
     section header and its first card fit on one screen. */
  :root{--sect:clamp(56px,13vw,80px)}

  body .wrap{padding-left:calc(20px + var(--sa-l));padding-right:calc(20px + var(--sa-r))}
  body .appshell{padding-left:calc(16px + var(--sa-l));padding-right:calc(16px + var(--sa-r))}

  /* Cards lose their generous inner padding before they lose their content. */
  body .mod,body .fcard{padding:18px}
  body .surf .headrow{padding:16px 18px 0}
  body .sechead{margin-bottom:clamp(28px,7vw,44px)}

  /* Footer: four columns to two is already handled at 920px; two to one
     needs to happen here or the link columns become 2-word wraps. */
  body .fgrid{grid-template-columns:1fr 1fr;gap:22px}
  body .fbrand{grid-column:1 / -1}
  body .fbrand p{max-width:none}
  body .disc{font-size:11.5px;text-align:left}

  /* The disclaimer is 11.5px in --mute — the smallest, lowest-contrast text
     on the platform, and it is the legally significant text. Left-aligned
     and stepped up here; the contrast fix belongs in app.css (see audit). */
  body .disc{line-height:1.7}
}

/* --- 390 / 414 ------------------------------------------------------------ */
@media(max-width:430px){
  body .greet{gap:12px}
  body .greet h1{font-size:clamp(24px,7vw,30px)}
  body .hero-copy{padding:20px}
  body .hero-copy .acts{gap:10px}
  body .hero-copy .acts .btn{flex:1 1 auto;min-width:calc(50% - 5px)}

  /* Six tiles at 3 columns = 2 rows; at 390px each tile is ~112px wide and
     the label "See it first" wraps to two lines while "Portfolio" does not,
     so the row's tiles have unequal heights. Fix the height. */
  body .tiles{gap:8px}
  body .tile{padding:14px 6px;min-height:82px;justify-content:center}
  body .tile span{font-size:10px;line-height:1.25}
}

/* --- 360 ------------------------------------------------------------------ */
@media(max-width:375px){
  body .wrap{padding-left:calc(16px + var(--sa-l));padding-right:calc(16px + var(--sa-r))}
  body .appshell{padding-left:calc(14px + var(--sa-l));padding-right:calc(14px + var(--sa-r))}
  body .d1{font-size:clamp(32px,9.5vw,40px)}
  body .d2{font-size:clamp(25px,7.5vw,29px)}
  body .lede{font-size:15.5px}

  body .navin{gap:10px;padding-top:11px;padding-bottom:11px}
  body .navin .logo img{height:21px}

  /* The proof strip at three items across a 328px content box gives each
     ~109px — "MEMBERS SO FAR" wraps to three lines. Two columns. */
  body .pitem{flex:1 1 45%;padding:8px 10px}
  body .pitem span{font-size:10px;letter-spacing:.12em}
}

/* --- 320: the floor -------------------------------------------------------
   Everything here is survival, not refinement. The goal is: no horizontal
   scroll, no clipped control, no text under 11px, every tap target reachable.
   ========================================================================== */
@media(max-width:340px){
  body .wrap{padding-left:calc(14px + var(--sa-l));padding-right:calc(14px + var(--sa-r))}
  body .appshell{padding-left:calc(12px + var(--sa-l));padding-right:calc(12px + var(--sa-r))}

  body .d1{font-size:30px;line-height:1.06}
  body .d2{font-size:23px}
  body .d3{font-size:20px}
  body .greet h1,body .phead h1{font-size:23px}

  /* Buttons stack rather than shrink — a 44px-tall pill with 8px of
     horizontal padding cannot hold "Create your free account". */
  body .cta{flex-direction:column;align-items:stretch;width:100%}
  body .cta .btn{width:100%}
  body .hero-copy .acts{flex-direction:column;align-items:stretch}
  body .hero-copy .acts .btn{width:100%}
  body .btn.lg{padding-left:18px;padding-right:18px;font-size:15px}

  /* Three tiles across at 296px = ~92px each. Two across is honest. */
  body .tiles{grid-template-columns:repeat(2,1fr)}

  /* The theme switch, search and avatar together are ~120px of a 296px nav
     alongside a 21px logo. Drop the search trigger — ⌘K is a desktop
     affordance and the tab bar carries navigation on a phone. */
  body .navright .kbd{display:none}
  body .navin .logo img{height:19px}
  body .av{width:28px;height:28px;font-size:11px}

  /* Footer goes single-column; two 132px columns cannot hold "Risk
     disclosure" on one line. */
  body .fgrid{grid-template-columns:1fr;gap:26px}

  /* The 404 shortcut grid and the modal footer. */
  body .grid{grid-template-columns:1fr}
  body .searchbtn{padding:12px 14px;font-size:14px}
  body .searchbtn .k{display:none}

  /* Avatar stacks overflow their row at this width. */
  body .avstack .a{width:26px;height:26px;font-size:10px;margin-left:-8px}
  body .avstack .more{font-size:11px;padding:3px 7px}
}


/* ==========================================================================
   §10  TABLET TIER — 768 / 834 / 1024
   --------------------------------------------------------------------------
   The gap in the current system. Every page jumps from a phone layout
   (single column, tab bar) straight to a desktop one at 900px, so iPad
   portrait — 768 and 834, a very common reading width for a lesson — gets
   the phone layout on a screen with 1024px of height and ample width.
   ========================================================================== */

@media(min-width:700px) and (max-width:899px){
  /* Restore two-column card grids that the pages collapsed at 700px. At
     768px a two-column .grid2 gives each card ~350px, which is comfortable
     and matches the desktop composition. */
  body .grid2{grid-template-columns:1fr 1fr;gap:16px}

  /* The member content column should not run the full 768px — a 700px+
     measure for 14px body copy is over 90 characters. */
  body .appshell{max-width:720px}

  /* The dashboard hero can hold its two-column form here. */
  body .hero-grid{grid-template-columns:1.15fr .85fr}
  body .media.tall{aspect-ratio:4/5}

  /* Marketing three-ups become two-ups rather than one-ups: three 240px
     cards are cramped, one 720px card is absurd. */
  body .three,body .rules,body .angles,body .roles{
    grid-template-columns:repeat(2,1fr);
  }
  body .three > *:last-child:nth-child(odd),
  body .rules > *:last-child:nth-child(odd),
  body .angles > *:last-child:nth-child(odd),
  body .roles > *:last-child:nth-child(odd){grid-column:1 / -1}

  /* The tab bar on a 768px screen should not stretch its five items across
     the full width — 153px per target is a long way for a thumb to travel
     and the labels float in space. Constrain and centre it. */
  body .tabs{
    max-width:520px;
    left:50%;right:auto;
    transform:translateX(-50%);
    border-radius:20px 20px 0 0;
    border-left:1px solid var(--hair);
    border-right:1px solid var(--hair);
  }
}

/* iPad landscape / small laptop — the sidebar appears here (>=900px, §4). */
@media(min-width:1024px) and (max-width:1279px){
  body .appshell{max-width:1000px}
  body .wrap{max-width:960px}
}

/* Touch-capable tablets get the coarse-pointer sizing from §3 automatically;
   this ensures the hover-only affordances have a visible fallback. */
@media(min-width:700px) and (hover:none){
  body .lrow .go{opacity:.55}
  body .toc a{min-height:44px;display:flex;align-items:center}
}


/* ==========================================================================
   §11  DESKTOP TIER — 1280 / 1440 / 1920 / 2560
   --------------------------------------------------------------------------
   The containers are `.wrap{max-width:1100px}` and
   `.appshell{max-width:1180px}`. Those are well judged for 1440 and start
   to look marooned above 1920: at 2560 the content occupies 43% of the
   screen and the eye has nothing to anchor to at the edges.

   The correction is NOT to let the layout stretch — a 2000px text column is
   unreadable. It is to let the container grow modestly, scale the type with
   it, and keep every text measure capped in ch. That way a large monitor
   gets more *air and image*, not longer lines.
   ========================================================================== */

@media(min-width:1280px){
  body .appshell{gap:48px}
}

@media(min-width:1440px){
  body .wrap{max-width:1180px}
  body .appshell{max-width:1260px;gap:52px}
  body .side{width:216px}
}

@media(min-width:1920px){
  body .wrap{max-width:1280px}
  body .appshell{max-width:1400px}
  /* Sections gain vertical air rather than horizontal sprawl. */
  :root{--sect:clamp(120px,7vw,168px)}
  /* Body copy steps up one notch — at a 1920px viewing distance 15px is
     small. Measures stay capped in ch so lines do not lengthen. */
  body .lede{font-size:19.5px}
  body .lbody p{font-size:17.5px}
  body .tcard p,body .mod p{font-size:15px}
}

@media(min-width:2560px){
  body .wrap{max-width:1360px}
  body .appshell{max-width:1480px}
  :root{--sect:clamp(140px,6vw,190px)}
  body .d1{font-size:82px}
  body .d2{font-size:56px}
  body .lede{font-size:21px}
  body .lbody p{font-size:18.5px}
  /* Everything text-bearing keeps its ch cap, so the extra width goes to
     the gutters and the media. */
  body .measure{max-width:72ch}
  body .lbody{max-width:66ch}
}

/* Retina / high-density: the film grain overlay in app.css is a 140px SVG
   tile at opacity .030–.045. On a 2x display it renders at half its
   intended scale and reads as noise rather than texture. */
@media(min-resolution:2dppx){
  body::after{background-size:210px 210px}
}
@media(min-resolution:3dppx){
  body::after{background-size:280px 280px;opacity:calc(var(--grain) * .8)}
}


/* ==========================================================================
   §12  LANDSCAPE PHONE
   --------------------------------------------------------------------------
   A 390x844 phone rotated is 844x390. Nothing on the platform is tuned for
   a 390px-TALL viewport, and three things break:

     1. `--sect` is `9.5vw` of 844 = 80px of padding top and bottom, so a
        section's header alone fills the screen.
     2. `.tabs` (62px) + the nav (50px) leave 278px of content.
     3. `.cmdk{padding:14vh 20px}` = 55px, and `.cmdlist{max-height:320px}`
        — together taller than the viewport, so the palette's footer is cut
        off and the last results are unreachable.
   ========================================================================== */

@media (orientation:landscape) and (max-height:500px){
  :root{--sect:44px}

  /* Reclaim vertical space from the chrome. */
  body .navin{padding-top:8px;padding-bottom:8px}
  body .navin .logo img{height:20px}
  body nav.stuck .navin{padding-top:6px;padding-bottom:6px}

  /* The tab bar becomes a slim icon row; labels are the first thing to go
     when height is the scarce resource. */
  body .tabs{padding-top:5px;padding-bottom:calc(6px + var(--sa-b))}
  body .tabs a{font-size:0;min-height:40px}
  body .tabs a .i{margin-bottom:0;font-size:17px}
  body .tabs .center .fab{width:44px;height:44px;top:-18px}
  body .tabs .center .fab svg{width:22px;height:22px}
  body[class].member{padding-bottom:calc(50px + 18px + var(--sa-b))}

  /* Hero sections stop being full-height statements. */
  body .hero{padding-top:32px;padding-bottom:26px}
  body .hero-logo{width:min(34%,180px);margin-bottom:18px}
  body .d1{font-size:clamp(28px,5vw,38px)}
  body .d2{font-size:clamp(22px,4vw,30px)}

  /* Command palette must fit. */
  body .cmdk{padding-top:5vh;padding-bottom:5vh;align-items:flex-start}
  body .cmdlist{max-height:44vh}

  /* Modal sheets: a bottom sheet on a 390px-tall screen leaves no room, so
     revert to the centred panel with an internal scroll. */
  body .ncc-modal{align-items:center;padding:12px}
  body .ncc-modal-panel{
    max-width:520px;border-radius:16px;border-bottom:1px solid var(--hair2);
    max-height:calc(100dvh - 24px);
  }
  body .ncc-modal-panel::before{display:none}
  body .ncc-modal-head{padding-top:18px}
  body .ncc-modal-foot{padding-top:14px;padding-bottom:14px}

  /* Toasts sit beside the content, not over it. */
  body .ncc-toasts{
    left:auto;
    right:calc(12px + var(--sa-r));
    width:min(340px,45vw);
    bottom:calc(56px + var(--sa-b));
    align-items:flex-end;
  }

  /* The dashboard's two-up grids have room again. */
  body .grid2{grid-template-columns:1fr 1fr}
  body .hero-grid{grid-template-columns:1.2fr .8fr}
}


/* ==========================================================================
   §13  PRINT
   --------------------------------------------------------------------------
   terms.html, privacy.html, standards.html and security.html are documents
   people print, save as PDF, and forward to a lawyer or a sceptical relative.
   Printed today they carry a black background in dark mode, a navigation
   bar, a footer of marketing links, a floating tab bar, and every link's
   destination invisible.

   This produces a clean document instead.
   ========================================================================== */

@media print{

  /* Force the light palette regardless of the on-screen theme. Redeclaring
     the tokens is the only way — the theme is applied by a [data-theme]
     attribute set from localStorage before paint. */
  html,html[data-theme="dark"],html[data-theme="light"]{
    --bg:#FFFFFF;--surface:#FFFFFF;--raised:#FFFFFF;--sunk:#FFFFFF;
    --text:#000000;--dim:#1A1A1A;--mute:#3A3A3A;
    --hair:#CCCCCC;--hair2:#999999;
    --btn-bg:#000000;--btn-fg:#FFFFFF;
    --sh-sm:none;--sh-md:none;--sh-lg:none;
    --glow:transparent;--edge:none;--spot:transparent;
    --grain:0;--ok:#000000;--ok-bg:transparent;--ok-bd:#999999;
  }

  *{
    background:transparent !important;   /* beats inline background styles */
    box-shadow:none !important;
    text-shadow:none !important;
    color:#000 !important;
  }

  body{
    background:#fff !important;
    font-size:11pt;
    line-height:1.5;
    padding:0 !important;
    -webkit-print-color-adjust:exact;
    print-color-adjust:exact;
  }

  /* Remove everything that is navigation, decoration or interaction. */
  nav,
  .tabs,
  .side,
  .stickybar,
  .cmdk,
  .viewtoggle,
  .seg,
  .kbd,
  .navright,
  .prog,
  .rprog,
  .ncc-toasts,
  .ncc-modal,
  .ncc-offline,
  .ncc-pagebar,
  .demo,
  .filt,
  .fgrid,
  .media,
  .phone,
  .dots,
  .avstack,
  .tiles,
  .ncc-skip,
  .banner,
  video,iframe,canvas{
    display:none !important;
  }

  /* The film grain overlay is a fixed pseudo-element — it would tile across
     every printed page. */
  body::after,body::before{display:none !important}

  /* Layout: single column, full width, no sticky anything. */
  .wrap,.appshell,.measure,.prose,.list,.qgroup,.lbody{
    max-width:none !important;
    width:auto !important;
    margin:0 !important;
    padding:0 !important;
    display:block !important;
    grid-template-columns:none !important;
    position:static !important;
  }
  section{padding:0 0 18pt !important}
  .surf,.card,.note,.ncc-alert{
    border:1px solid #CCC !important;
    border-radius:0 !important;
    padding:10pt !important;
    margin:0 0 10pt !important;
  }

  /* Typography for paper. Serif display stays; body copy goes to a size
     that holds on an A4 measure. */
  h1,.d1{font-size:22pt;line-height:1.15;margin:0 0 8pt}
  h2,.d2{font-size:16pt;line-height:1.2;margin:16pt 0 6pt}
  h3,.d3{font-size:13pt;margin:12pt 0 4pt}
  p,li,.lede,.srow p,.qbody p{font-size:11pt;line-height:1.5;margin:0 0 7pt}
  .kicker,.idx,.lbl,.k{font-size:8pt;letter-spacing:.12em}
  .disc{font-size:8.5pt;line-height:1.45;text-align:left;max-width:none}

  /* Reveal link destinations — the whole point of printing a legal page is
     that the references remain checkable. Internal anchors are skipped,
     since "#risk" on paper is noise. */
  a[href^="http"]::after{
    content:" (" attr(href) ")";
    font-size:8.5pt;
    color:#444 !important;
    word-break:break-all;
  }
  a[href^="#"]::after,
  a[href^="mailto"]::after{content:""}
  a{text-decoration:underline}

  /* FAQ and any <details> must print OPEN — a collapsed answer on paper is
     a blank space where the answer should be. */
  details{display:block !important}
  details > summary{
    display:block !important;
    font-weight:600;
    list-style:none;
    margin-bottom:4pt;
  }
  details > summary::-webkit-details-marker{display:none}
  details:not([open]) > *:not(summary){display:block !important}
  /* faq.html uses a class-toggled accordion rather than <details>. */
  .qbody{display:block !important;height:auto !important;
         max-height:none !important;overflow:visible !important;opacity:1 !important}
  .qhead{page-break-after:avoid;break-after:avoid}

  /* Pagination discipline. */
  h1,h2,h3,h4,.d1,.d2,.d3,.sechead{
    page-break-after:avoid;break-after:avoid-page;
  }
  p,li,blockquote,.srow,.row{
    orphans:3;widows:3;
    page-break-inside:avoid;break-inside:avoid;
  }
  .surf,.card,.qgroup > *{page-break-inside:avoid;break-inside:avoid}
  section{page-break-before:auto}

  /* A printed legal document needs to identify itself. The URL and the
     retrieval date are what make a printout citable. */
  @page{
    margin:18mm 16mm;
  }
  .lbody::after,
  .prose::after{
    content:"";
  }
  /* Add this once per legal page, in the HTML, for a proper colophon:
     <p class="ncc-print-only">Retrieved from nextcoinclub.com — this
     document is versioned; check the site for the current text.</p> */
  .ncc-print-only{display:block !important;
    font-size:8.5pt;color:#444 !important;margin-top:14pt;
    padding-top:8pt;border-top:1px solid #CCC}
}

/* Hidden on screen, shown on paper. */
.ncc-print-only{display:none}
/* Shown on screen, hidden on paper. */
@media print{.ncc-screen-only{display:none !important}}
