/* GENERATED by build_guide_theme.py from ui.py -- do not edit by hand.
   1.0.5: rebuilt by the recreated script (s49); the top part is
   ui.TOKENS_ROOT + ui.BAR_CSS as they stand, the rest is carried from
   the previous theme. */

 :root{
   /* One hue per meaning. Nothing here is decorative: indigo is action and
      progress, teal is verified fact, amber is "the model guessed", crimson
      is "do not rely on this". A reader learns the code once and it holds
      everywhere -- in tags, grades, banners and step states alike.
      Carried here from the tool page's own copy when the three copies of
      this block were collapsed into one; it was the only place it was
      written down. */
   --ink:#101828; --ink2:#35415c; --muted:#6b7690;
   --paper:#e9edf4; --panel:#fff; --rule:#d3dae7; --rule2:#e6ebf3;
   --indigo:#33449b; --indigo-dk:#26337a; --indigo-tint:#eff1fc;
   --teal:#0d7267;   --teal-tint:#e4f3f0;
   --amber:#9d6208;  --amber-tint:#fdf3e1;
   --crimson:#a72440;--crimson-tint:#fdedf0;
   --grid:rgba(51,68,155,.055);
   --shadow:0 1px 2px rgba(16,24,40,.05),0 6px 18px -8px rgba(16,24,40,.13);
   --mono:ui-monospace,"SF Mono",Consolas,"Liberation Mono",monospace;

   /* ------------------------------------------------------------------
      SEMANTIC LAYER. Everything above this line is the original palette and
      stays until each of its uses has been migrated. Everything below names
      a ROLE rather than a hue, so a theme can change the hue without any
      name becoming a lie.

      NOT THEMED, BY DECISION: generated report PDFs and receipt PDFs. They
      carry their own independent design and import none of this. A report
      goes to third parties and a receipt is a financial document; neither
      may change appearance because somebody picked a theme.
      ------------------------------------------------------------------ */

   /* Neutral ramp. Replaces the thirty-one distinct near-white greys that
      were scattered across the page stylesheets. Luminance falls
      monotonically -- asserted by the patch, because a ramp that reverses
      anywhere makes "one step darker" stop meaning one step darker. Five
      steps ARE existing values, so migrating on to them moves nothing. */
   --n-0:#ffffff;  --n-50:#fafbfd;  --n-100:#f2f5fa; --n-150:#e9edf4;
   --n-200:#e6ebf3; --n-300:#d3dae7; --n-400:#b6bfd0; --n-500:#8a94a8;
   --n-600:#5b667f; --n-700:#4a5570; --n-800:#35415c; --n-900:#101828;

   /* Surfaces */
   --canvas:var(--n-150);
   --surface:var(--n-0);
   --surface-hover:var(--n-50);
   --surface-sunken:var(--n-100);

   /* Text. --text-muted is deliberately DARKER than the existing --muted:
      --muted measures 3.87 on the page background where 4.5 is required. */
   --text:var(--n-900);
   --text-2:var(--n-800);
   --text-muted:var(--n-600);
   --text-on-accent:#ffffff;   /* a token, because a pale accent needs dark text */

   /* Lines */
   --border:var(--n-300);
   --border-soft:var(--n-200);
   --border-strong:var(--n-400);

   /* Accent */
   --accent:#33449b; --accent-strong:#26337a; --accent-tint:#eff1fc;

   /* Status. The -strong steps were already loose in the stylesheets with no
      name -- #9b1c2e twenty times, #9a5b0b four, #1a6b33 four -- which is how
      they drifted away from the colour they are a variant of. */
   --danger:#a72440;  --danger-strong:#8c1c33;  --danger-tint:#fdedf0;
   --warn:#9d6208;    --warn-strong:#7f4f06;    --warn-tint:#fdf3e1;
   --success:#0d7267; --success-strong:#0a5c53; --success-tint:#e4f3f0;

   /* Disabled. Today a disabled button is white on #aab3c6, a ratio of 2.11
      against a required 4.5 and the worst-measuring thing on the site. This
      pairing measures 6.27 and reads as unavailable rather than as broken. */
   --disabled-surface:var(--n-200);
   --disabled-text:var(--n-700);
   --disabled-border:var(--n-300);

   /* Radius, by the size of the thing rather than by the page it is on. */
   --r-1:6px; --r-2:8px; --r-3:12px; --r-pill:999px;

   /* Space, on a 4px scale. */
   --sp-1:4px; --sp-2:8px; --sp-3:12px; --sp-4:16px;
   --sp-5:20px; --sp-6:24px; --sp-7:32px; --sp-8:40px;

   /* Control sizes. Height is a token so a button and the select beside it
      line up without anybody nudging a padding. Measured today: five
      distinct control heights in a single row. */
   /* THE SMALL CONTROL SIZE, AS IT IS TODAY -- padding and type, not height.
     Six rules across five stylesheets used to retype these two values. One
     of them carried a comment saying "a size invented on the spot because
     there was nothing to reuse -- there is now", and then restated the
     numbers, because CSS offered no way to point at button.sm from another
     sheet. This is that way.
     These are the CURRENT values and nothing moves by adopting them.
     Deliberately NOT --ctl-h-sm below, which is a HEIGHT and holds a
     proposed 30px against the real 31.4px. Sizing by height overrides a
     page's own padding without saying so. */
  /* THE HEIGHT OF A ROW OF CONTROLS.
     A filter row mixes text inputs, date inputs and selects, and those three
     have DIFFERENT INTRINSIC HEIGHTS at identical padding -- measured on the
     Costs row, one padding rule produced 36.14, 38.14 and 33. A row can only
     be made to line up by declaring a height.
     This does NOT reopen the rule against height on the SHARED control rule.
     That rule stands and was earned: select{height:43.3px} on the base
     overrode .payctl's deliberate 29px and blew up three selects on
     Accounts. A height scoped to one named row cannot leak.
     36px because four of the nine controls on the Costs row are already
     36.14, so it is the value that moves the row least. */
  --ctl-row-h:36px;
  /* A DENSER ROW, FOR CONTROLS IN A PANEL HEADING.
     .payctl on Accounts carries the reason: "SMALLER THAN A FORM CONTROL.
     These sit in a panel heading, not in a form, and full-sized inputs there
     read as something to fill in." At --ctl-row-h they would be 7.3px from
     the form control they are meant to read as smaller than, which drops
     that decision without saying so.
     32px because the panel heading already puts .sm buttons beside these --
     #payclearf is class="quiet sm payclr" at 31.4px -- so the rule reads as
     "a content row uses the row height, a panel heading uses the small one"
     rather than as one more number. */
  --ctl-row-h-sm:32px;
  --ctl-sm-pad:5px 11px;
  --ctl-sm-font:12.5px;
  --ctl-h-sm:30px; --ctl-h:38px; --ctl-h-lg:44px;

   /* Type */
   --fs-xs:12px; --fs-sm:13px; --fs-md:15px;
   --fs-lg:17px; --fs-xl:21px; --fs-2xl:27px;

   /* Elevation. Panels carry a shadow; buttons do not. */
   --shadow-1:0 1px 2px rgba(16,24,40,.05),0 6px 18px -8px rgba(16,24,40,.13);
   --shadow-2:0 12px 32px -12px rgba(16,24,40,.28);
   --focus-ring:0 0 0 3px rgba(51,68,155,.32);

   /* Data fills: the funnel, the disclosure bars, the sparkline, the
      hourly chart, the key meters. The accent two steps lighter, so a
      chart reads as the same family as the buttons without competing
      with them. Teal was considered and refused: it already means
      verified/confirmed/paid in 64 places, and a teal bar beside a
      teal badge reads as a status the row does not have. */
   --chart-1:#7d8ac6;
   /* NOT the same thing as a chart. A run in flight and the report
      timeline say "this is happening", which is the accent's job.
      Separate so that restyling every chart cannot silently recolour
      the bar a customer watches while their report builds. Defined
      here, wired up in its own patch. */
   --progress:var(--accent);

   /* NOT a custom property -- a real one, set here because it is
      inherited, so one declaration on :root reaches every native
      control on the page. Checked checkboxes, selected radios and
      slider fills were all drawing in the browser's own blue: 28
      checkboxes, 12 radios and 2 sliders, none of which knew the
      palette existed.
      Scoping it to input[type=range] was considered and refused. The
      sliders on Metrics -> Server were what got noticed, but the
      checkboxes on Costs, Your Data, Users, Accounts and the tool
      page's filter row have the same problem, and fixing the two that
      were seen while leaving forty that were not is how a palette
      drifts.
      This is the first thing to benefit from patch 1: because the
      three copies of this block are now one, this single line also
      reaches the tool page and the login page, which do not render
      through ui.page(). */
   accent-color:var(--accent);
 }

 /* --- app bar --- */
 .appbar{background:var(--panel);border-bottom:1px solid var(--rule);
   box-shadow:var(--shadow);position:sticky;top:0;z-index:40}
 .appbar .inner{max-width:1240px;margin:0 auto;padding:0 24px;
   display:flex;align-items:center;gap:20px;height:58px}
 /* SAFE AREA. Turn a notched phone on its side and the display extends under
    the rounded corners and the camera housing, so a bar padded by a flat 24px
    puts the logo underneath the curve. env() is 0 wherever it does not apply,
    so desktops and older phones are untouched.
    max() rather than adding the two: the inset already exceeds 24px on most
    devices, and adding would indent the contents twice. */
 @supports(padding:max(0px)){
   .appbar .inner{padding-left:max(24px, env(safe-area-inset-left));
                  padding-right:max(24px, env(safe-area-inset-right))}
 }
 .brand{display:flex;align-items:center;gap:10px;text-decoration:none;color:var(--ink);
   flex:none}
 /* THE IP FOLKS LOGO (s48, owner). It replaced a 30px mark beside the old
    product name in words: the owner's logo carries the name, so the words
    went with it (and the site's name in text became IP Folks, brand_name). The mark with "IP Folks", 44px tall (.bname in BRAND): the
    name comes out about 11px tall, the size the old wordmark's letters were.
    AT EVERY WIDTH (owner, s48). The mark alone was shown below 420px for an
    hour and the owner, looking at it on his phone, preferred the name: the
    logo is 99px wide, narrower than the old wordmark, and fits down to
    320px (measured -- see the 420px block).
    THE TAGLINE VERSION WAS RENDERED HERE AND REFUSED (owner, s48): in a 58px
    bar its "Partners in Innovation" is about 3px tall, and a bar tall enough
    to read it (about 100px) costs every page that much height. It is on the
    sign-in cards instead, where it is 300px wide.
    SCOPED TO .appbar: the sign-in page has a second .brand, in its card,
    with rules of its own.
    HEIGHT ONLY, width auto, so the pictures keep their own proportions; the
    width and height attributes in BRAND reserve the space before they load. */
 .appbar .brand img{display:block;width:auto}
 .appbar .brand .bname{height:44px}
 /* Pushed to the right so the links sit with the account button rather than
    crowding the wordmark. flex:1 made the nav claim all the space after the
    brand, which planted the first link against the logo and left a gap the
    width of the bar on the other side. margin-left:auto gives the nav only
    the width it needs and puts the empty space where empty space belongs. */
 .nav{display:flex;gap:5px;margin-left:auto;min-width:0}
 .nav a{display:inline-block;padding:7px 13px;border-radius:8px;font-size:13.5px;
   font-weight:600;color:var(--ink2);text-decoration:none;white-space:nowrap}
 .nav a:hover{background:#f1f4f9;color:var(--ink)}
 .nav a.on{background:var(--indigo-tint);color:var(--indigo-dk)}

 /* The menu button. Absent on wide screens, where the links fit. */
 /* .appbar-qualified, not bare .navtoggle. Every page carries a base
    `button{background:var(--indigo);color:#fff}` rule, and on the tool page
    that stylesheet is loaded after this one -- so a plain class selector lost
    and the menu button rendered as a solid indigo square with an invisible
    icon. */
 .appbar .navtoggle{display:none;align-items:center;justify-content:center;
   width:38px;height:38px;padding:0;border:1px solid var(--rule);
   border-radius:9px;background:var(--panel);color:var(--ink2);
   cursor:pointer;flex:none;margin-left:auto;box-shadow:none}
 .appbar .navtoggle svg{width:19px;height:19px;fill:none;stroke:currentColor;
   stroke-width:1.9;stroke-linecap:round}
 .appbar .navtoggle:hover{background:var(--indigo-tint);color:var(--indigo-dk);
   border-color:var(--indigo)}

 /* The bar's own responsive rules live HERE, in BAR_CSS, because the tool
    page loads only this block -- PAGE_CSS is for the shell pages. Putting
    them in the wrong one gave the tool page a menu button it never showed
    and a nav that stayed a wrapped row. */

 /* Colour carries the state of the FURTHEST draft, so the badge says more
    than "three things are unfinished". Teal means one is confirmed and a
    minute from a report -- work already paid for. */
 .navbadge{display:inline-block;background:var(--muted);color:#fff;border-radius:99px;
   font-size:10.5px;font-weight:700;padding:1px 6px;margin-left:5px;vertical-align:1px}
 .navbadge.analysed{background:var(--amber)}
 .navbadge.confirmed{background:var(--teal)}
 .navbadge.searching{background:var(--indigo)}
 .userbox{position:relative;flex:none}
 .userbtn{display:flex;align-items:center;gap:9px;background:transparent;border:1px solid var(--rule);
   border-radius:99px;padding:5px 11px 5px 6px;cursor:pointer;font:inherit;color:var(--ink)}
 /* THE SIGN-IN CONTROL TAKES THE SAME SLOT AS .userbtn ABOVE, so it is
    the same shape. Before 8 September it came straight from CONTROLS_CSS
    at 43.25px with an 8px radius -- correct for a form control, wrong
    here: the tallest thing in a 59px bar and the only square-cornered
    one, beside 34.92px nav links and a 38px pill. guestbar()'s docstring
    says the bar exists so that signing in does not feel like landing on
    a different site, and this is the one element that broke that.

    NOT FILLED INDIGO. That version was rendered and refused: this bar
    navigates rather than persuades -- the same reason GUEST_JS records
    for removing the sign-up button from it -- and a filled button here
    competes with the intake box, which is what the visitor came for.

    height rather than padding alone, because the height has to match
    .userbtn exactly and .userbtn's own height is whatever its avatar
    and 5px padding come to. inline-flex so the label centres against a
    stated height instead of a line box. */
 .appbar .userbox .btn{display:inline-flex;align-items:center;height:38px;
   padding:5px 16px;border-radius:99px;font-size:15px}
 /* The whole control inverts on hover, so every part of it has to move --
    the name, the caret and the avatar. Tinting only the background left black
    text on a coloured chip, which reads as a rendering fault rather than a
    hover state. */
 .userbtn:hover{background:var(--indigo);border-color:var(--indigo);color:#fff}
 .userbtn:hover .nm,.userbtn:hover .cv{color:#fff}
 .userbtn:hover .avatar{background:#fff;color:var(--indigo)}
 .userbtn:hover img.avatar{box-shadow:0 0 0 2px #fff}
 .userbtn{transition:background .12s ease,border-color .12s ease,color .12s ease}
 .avatar{width:26px;height:26px;border-radius:50%;background:var(--indigo);color:#fff;
   display:grid;place-items:center;font-weight:700;font-size:12px;flex:none;
   object-fit:cover;overflow:hidden}
 img.avatar{background:#e8ecf4}
 .userbtn .nm{font-size:13px;font-weight:600}
 .userbtn .cv{color:var(--muted);font-size:10px}
 /* OPEN REQUESTS on the name button (s45). Positioned against the button,
    so the button is the containing block; nothing else in it is positioned. */
 .userbtn{position:relative}
 .userbtn .reqdot{position:absolute;top:-5px;right:-5px;min-width:17px;height:17px;
   line-height:13px;box-sizing:border-box;border-radius:99px;background:var(--amber);
   color:#fff;font-size:10.5px;font-weight:700;text-align:center;padding:0 4px;
   border:2px solid var(--panel)}
 .menu{position:absolute;right:0;top:calc(100% + 7px);background:var(--panel);
   border:1px solid var(--rule);border-radius:11px;box-shadow:0 16px 40px rgba(16,24,40,.19);
   min-width:210px;padding:7px;display:none;z-index:50}
 .menu.open{display:block}
 .menu .who{padding:9px 11px 10px;border-bottom:1px solid var(--rule2);margin-bottom:5px}
 .menu .who .n{font-weight:650;font-size:13.5px}
 .menu .who .r{font-size:11.5px;color:var(--muted);margin-top:2px}
 .menu a,.menu button{display:block;width:100%;text-align:left;padding:8px 11px;
   border:0;background:transparent;border-radius:7px;font:inherit;font-size:13.5px;
   color:var(--ink);cursor:pointer;text-decoration:none}
 .menu a:hover,.menu button:hover{background:#f3f5fa}
 /* SIGN OUT (s48, owner): plain text like the items above it, set apart by a
    thin rule instead of colour, with the same light hover.
    It was crimson, and on hover it went dark indigo -- crimson on indigo,
    unreadable. The indigo was never chosen for it: Sign out is the menu's
    only <button> (it has to POST), and PAGE_CSS's
    button:hover:not(:disabled) weighs (0,2,1), the same as .menu
    button:hover above, and comes later, so it won. .menu button.out:hover
    weighs (0,3,1) and wins wherever the stylesheets are loaded in whatever
    order. Crimson is dropped too: on this site it means "do not rely on
    this", and signing out loses nothing. White on the dark indigo was
    offered by the owner and considered: legible, but a filled item is how
    a menu marks the selected or primary entry, and Sign out is neither. */
 .menu button.out{position:relative;margin-top:11px}
 .menu button.out::before{content:"";position:absolute;left:0;right:0;top:-6px;
   border-top:1px solid var(--rule2)}
 .menu button.out:hover{background:#f3f5fa;color:var(--ink)}
 .role{display:inline-block;font-size:10px;font-weight:700;text-transform:uppercase;
   letter-spacing:.06em;border-radius:99px;padding:2px 8px;
   border:1px solid var(--rule);color:var(--muted)}
 .role.admin{border-color:var(--indigo);color:var(--indigo);background:var(--indigo-tint)}

 /* One tooltip element, parented to <body>. Anything with data-tip gets it. */
 #tip{position:fixed;z-index:9999;max-width:300px;background:var(--ink);color:#fff;
   font:400 12px/1.45 ui-sans-serif,system-ui,sans-serif;letter-spacing:0;
   text-align:left;text-transform:none;padding:8px 10px;border-radius:8px;
   box-shadow:0 8px 24px rgba(16,24,40,.3);pointer-events:none;
   opacity:0;transition:opacity .1s ease;display:none}
 #tip.on{display:block;opacity:1}
 #tip::after{content:"";position:absolute;left:var(--ax,50%);
   border:5px solid transparent}
 #tip.below::after{bottom:100%;border-bottom-color:var(--ink)}
 #tip.above::after{top:100%;border-top-color:var(--ink)}

 /* MOBILE, LAST ON PURPOSE.
    These override base rules of equal specificity -- .menu against
    .menu -- so they are decided by source order, and a media query
    placed earlier in the file loses to a plain rule placed later.
    Keeping the block at the end of the stylesheet is what makes it
    behave the way anyone reading it would expect. */
 @media(max-width:760px){
   .appbar .inner{height:58px;padding:0 16px;gap:10px}

   /* THE ACCOUNT MENU AS A SHEET.
      It was a desktop dropdown that happened to fit -- 210px of a 390px
      screen, hanging over the page beneath -- while the navigation beside it
      opened as a full-width panel. Two menus in one bar behaving differently
      is one of them being an afterthought. */
   /* FIXED, not absolute. The menu is positioned against .userbox, which is
      about 100px wide -- so left:12px/right:12px measured from THAT and made
      the sheet narrower rather than wider, wrapping every item onto three
      lines. Fixed positions it against the viewport, which is what "full
      width" has to mean. */
   .menu{position:fixed;left:12px;right:12px;top:64px;min-width:0;padding:8px}
   .menu a,.menu button{padding:13px 14px;font-size:14.5px}
   /* !important, and not lightly: several pages set their own input sizes
      with heavier selectors, and below 16px iOS zooms the whole page on
      focus. That zoom is a threshold rather than a preference -- one pixel
      smaller and the page jumps, and the reader has to pinch back out. */
   input,select,textarea{font-size:16px !important}

   /* TAP TARGETS. 44px is the smallest a finger reliably hits: Apple's
      figure, and Android asks for 48. Everything measured here was 36 to 38,
      which is a mouse measurement that nobody had questioned. */
   button,.btn,input,select,textarea{min-height:44px}
   /* 16px or smaller makes iOS zoom the page on focus, which then has to be
      pinched back out. The zoom is not a preference, it is a threshold. */
   input,select,textarea{font-size:16px}

   /* TABLES SCROLL rather than overflow. A 640px table in a 390px viewport
      pushed the entire page sideways, so every page scrolled horizontally
      and the layout read as broken. Confining the scroll to the table keeps
      the page still and the columns legible. */
   .body2,.tablewrap{overflow-x:auto;-webkit-overflow-scrolling:touch}
   .body2 table{min-width:560px}
   .appbar .navtoggle{display:flex}
   /* THE SIGNED-OUT SIGN-IN, AT THE RIGHT -- by the menu button's own
      margin-left:auto, as in the signed-in bar.
      Session 17 gave .userbox.guest a margin-left:auto here, because the
      signed-out bar had no menu button then and nothing pushed Sign in off
      the brand. Session 19 gave that bar the button, and from then on the
      TWO auto margins split the free space: the menu button floated in the
      middle of the bar, which the note that stood here had predicted for
      the signed-in bar. The old, wider wordmark hid most of the gap; the
      IP Folks logo showed it and the owner found it (s48). NOW margin-left:0,
      here and in the .compact rules below: stated rather than deleted, so
      the rule is still there to read and test_nav_fit.py still holds the
      two places to the same declarations. */
   .appbar .userbox.guest{margin-left:0}

   /* A PANEL, not a wrapped row.
      The links used to become a third line inside the bar with its own
      horizontal scroll -- which on a narrow screen sat under the account
      button and read as overlapping rather than as a menu. A panel that
      opens below the bar is what a person expects from a menu button, and it
      cannot collide with anything because it is not in the bar at all. */
   .nav{position:absolute;top:58px;left:0;right:0;display:none;
     flex-direction:column;gap:2px;background:var(--panel);
     border-bottom:1px solid var(--rule);box-shadow:0 12px 24px rgba(16,24,40,.10);
     padding:8px 12px 12px;margin:0}
   .nav.open{display:flex}
   .nav a{padding:11px 13px;font-size:14.5px}
 }

 /* THE BRAND AT NARROW WIDTHS -- the 420px block below.
    IN BAR_CSS because the tool page loads only this block -- PAGE_CSS is for
    the shell pages. An earlier rule lived in PAGE_CSS, so the brand changed
    on Drafts and Reports and not on the tool page: the page-to-page
    inconsistency this shell was built to prevent.
    Until s48 the old wordmark SHRANK here rather than going, on the argument
    that a mark with blank space beside it reads as something that failed to
    load. The IP Folks logo neither shrinks nor goes: the owner tried the
    mark alone on a phone and chose the logo with the name (s48). Measured in
    Chromium at 320, 360, 390 and 420px, signed in and signed out: nothing
    scrolls sideways. */
 /* A NAV THAT STAYS A ROW (session 19). The 760px block above turns .nav
    into a panel that only opens with .open, which is right for a bar with a
    menu button and wrong for one carrying a single link -- the auth pages,
    where Help is the whole navigation and somebody locked out needs it in
    one tap, not two.

    IT WINS BY SPECIFICITY, NOT BY ORDER. `.appbar .nav.always` outweighs the
    block's bare `.nav`, so it applies wherever it is placed -- checked in a
    browser both ways rather than reasoned about, after a first version of
    this comment claimed the opposite. It is written after the block anyway,
    so it reads in the order it takes effect.

    Only this class is affected; .nav everywhere else is untouched. */
 .appbar .nav.always{position:static;display:flex;flex-direction:row;
   background:none;border:0;box-shadow:none;padding:0;margin-left:auto}
 .appbar .nav.always a{padding:7px 13px;font-size:14px}

 /* THE BAR FOLDS WHEN ITS LINKS DO NOT FIT (s44), at ANY width.
    The 760px block below was the only switch to the menu, and at about 960px
    an administrator's nine links ran under the account button: .nav may
    shrink narrower than its links (min-width:0), so a crowded row spills
    over its neighbour instead of pushing it. MENU_JS measures the row and
    sets .compact on the bar when it overflows; these are the 760px block's
    nav rules, word for word, keyed to that class.
    :not(.always) -- the sign-in pages' one-link bar stays a row (s19).
    .userbox.guest: margin-left 0, not auto, since s48 -- see the 760px block.
    Specificity (0,4,0) outweighs the bare .nav rules and .nav.always. */
 .appbar.compact .navtoggle{display:flex}
 .appbar.compact .userbox.guest{margin-left:0}
 .appbar.compact .nav:not(.always){position:absolute;top:58px;left:0;right:0;
   display:none;flex-direction:column;gap:2px;background:var(--panel);
   border-bottom:1px solid var(--rule);box-shadow:0 12px 24px rgba(16,24,40,.10);
   padding:8px 12px 12px;margin:0}
 .appbar.compact .nav.open:not(.always){display:flex}
 .appbar.compact .nav:not(.always) a{padding:11px 13px;font-size:14.5px}

 @media(max-width:420px){
   .userbtn .nm{max-width:60px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
 }

 /* Below 360px the row above still does not fit. At 320px it needs about
    375px, so the whole document could be dragged sideways -- on every page,
    because this stylesheet is on every page. That width is the reflow width
    WCAG asks for and is what a 1280px desktop becomes at 400% zoom, so this
    is mostly about somebody zooming, not about old handsets.

    The brand here is the logo with the name, as at every width (s48).

    What this gives up, at this width only: the role caption under the name,
    and a few more characters of the username. Both are in the menu the button
    opens, so nothing becomes unreachable.

    The signed-out and auth bars carry the same brand as the signed-in one --
    deliberately, so the bar does not change at the moment somebody signs
    in. That page-to-page consistency is what this shell exists
    for.

    Measured in Chromium at 320px: document scrollWidth 320, no sideways
    scroll, tap targets still 44px. 360px and above are untouched. */
 @media(max-width:359px){
   .userbtn .cv{display:none}
   .userbtn .nm{max-width:44px}
 }
 /* --- site footer (s43) ---
    IN BAR_CSS ON PURPOSE: it is the only stylesheet every page loads.
    The bottom padding clears a phone's home indicator; env() is 0
    wherever it does not apply. */
 .sitefoot{border-top:1px solid var(--rule);margin-top:28px;
   padding:10px 24px calc(10px + env(safe-area-inset-bottom,0px));
   font-size:13px;color:var(--muted)}
 .sitefoot .inner{max-width:1240px;margin:0 auto;display:flex;
   flex-wrap:wrap;align-items:center;gap:0 18px}
 .sitefoot .co{margin-right:auto}
 /* 32px tall so a thumb can hit a link without hitting its neighbour. */
 .sitefoot a{color:var(--muted);text-decoration:none;
   display:inline-flex;align-items:center;min-height:32px}
 .sitefoot a:hover{color:var(--ink);text-decoration:underline}

 /* From ui.CONTROLS_CSS, scoped to the bar (see the build script). */
 .appbar .btn{background:var(--indigo);color:#fff; border:1px solid transparent;border-radius:8px; padding:9px 15px;font:inherit;font-weight:600;cursor:pointer; text-decoration:none;display:inline-block; box-shadow:0 1px 2px rgba(16,24,40,.16)}
 .appbar .btn:hover{background:var(--indigo-dk)}
 .appbar .btn.ghost{background:#fff;color:var(--indigo);border:1.5px solid var(--indigo); box-shadow:none}
 .appbar .btn.ghost:hover{background:var(--indigo-tint)}

/* ============================================================================
   THE INVENTOR'S GUIDE -- the theme's own rules (build_guide_theme.py).
   Loaded AFTER Source's screen.css, so where both set a property, this wins.
   ========================================================================= */

/* The tool's font: the system stack, nothing downloaded. Source defaults to
   Inter and EB Garamond; these variables are what its text uses. */
:root{
  --font-sans: ui-sans-serif, system-ui, "Segoe UI", Roboto, sans-serif;
  --font-serif: ui-sans-serif, system-ui, "Segoe UI", Roboto, sans-serif;
}
/* THE INDIGO ACCENT, whatever Ghost's Brand setting says. html:root outweighs
   the :root rule {{ghost_head}} writes after this file. To let the Brand
   setting choose instead, delete this rule. */
html:root{--ghost-accent-color:#33449b}

/* The tool's paper-and-grid background. */
body{
  background-color:var(--paper);
  background-image:linear-gradient(var(--grid) 1px,transparent 1px),
                   linear-gradient(90deg,var(--grid) 1px,transparent 1px);
  background-size:22px 22px;
  color:var(--ink);
}

/* Source's `.nav a{display:inline-flex}` reaches the bar's links too. Same
   weight as the bar's own rule, which comes later and wins -- stated here as
   well, so a reordering cannot silently change the bar. */
.appbar .nav a{display:inline-block}

/* The markers Source's script needs (see the build script). */
.gh-navigation.ipf-marker{display:none}
.gh-footer.ipf-marker{display:block;height:0;margin:0;padding:0;border:0}

/* THE SEARCH BUTTON IN THE BAR: the same round, outlined shape as the
   bar's menu button, so the two read as one family. */
.appbar .gh-search{display:inline-flex;align-items:center;justify-content:center;
  width:38px;height:38px;padding:0;border:1px solid var(--rule);border-radius:9px;
  background:var(--panel);color:var(--ink2);cursor:pointer;flex:none}
.appbar .gh-search:hover{background:var(--indigo-tint);color:var(--indigo-dk);
  border-color:var(--indigo)}
.appbar .gh-search svg{width:18px;height:18px}
/* Ghost's menu, if ever used again (partials/navigation.hbs). */
.ipf-gnav{display:flex;flex-wrap:wrap;gap:4px 14px;list-style:none;margin:0;padding:0}

/* THE NOTE UNDER EVERY ARTICLE. As wide as the text above it, so its edges
   line up with the paragraphs (s45: follows --content-width, was 720px).
   WIDTH, NOT MAX-WIDTH: with max-width alone it ran edge to edge on phones,
   because it sits outside the .gh-canvas grid that gives the text its side
   gaps; the same gap is subtracted here (found s45, present before). */
.ipf-disclaimer{max-width:none;margin:32px auto 0;
  width:min(var(--content-width,720px), 100% - 2 * var(--container-gap));padding:14px 16px;
  border:1px solid var(--rule);border-radius:10px;background:var(--panel);
  font-size:14px;line-height:1.55;color:var(--ink2)}

/* ARTICLE WIDTHS (s45, owner). Posts and pages only: nothing else uses
   Source's .gh-canvas grid, so the home page and tag pages are unchanged.

   TEXT COLUMN 880px, not Source's 720px. About 85 characters a line on a
   laptop -- at the upper end of comfortable reading, chosen by the owner so
   long technical articles need less scrolling. 1040px (~100 characters) was
   measured and not chosen: past ~90 the eye loses its place returning to the
   next line. Set on :root because Source reads it with a 720px fallback and
   declares it nowhere itself.

   THE HEADING SPANS THE FEATURE IMAGE (1120px), not the text column. Tag,
   title and the date/share line sit in the grid's "wide" column, the same
   column as .gh-article-image, so the title's left edge meets the picture's.
   The excerpt keeps Source's own max-width:720px: it starts at the same left
   edge but stays a readable paragraph rather than one 1120px line.

   PHONES: below 880px + margins the grid's main column is already the whole
   width less the gaps, and "wide" collapses to nothing, so nothing moves. */
:root{--content-width:880px}
.gh-article{--container-width:1120px}
.gh-article-header>.gh-article-tag,
.gh-article-header>.gh-article-title,
.gh-article-header>.gh-article-excerpt,
.gh-article-header>.gh-meta-share{grid-column:wide}

/* THE SIGNED-IN BUTTON ON PHONES (1.0.3, s46, owner).
   A reader signed in to the tool gets "Start a prior-art search" in place of
   "Sign in" (ipfolks.js, which also sets .ipf-in on the bar).

   ABOVE 760px it stays in the bar: measured with room to spare down to 761px.

   AT 760px AND BELOW the bar holds the logo, the menu button, search and
   this, and there is not room: about 84-91px is left for it at 360-375px,
   and the label is about 196px. So for a signed-in reader it leaves the bar
   and appears at the foot of the menu panel instead, full width. "Open the
   tool" in 1.0.2 was already running off the screen on most phones (found
   s46, measured: 16px at 375, 31px at 360).

   A SHORTER LABEL WAS CONSIDERED AND REFUSED: even "Open the tool" does not
   fit, and "Search" would be read as the Guide's own search button beside it.
   HIDING THE WORDMARK WAS NOT CONSIDERED AGAIN: ui.py records that decision
   (shrink it, never hide it) and why. (1.0.4: the IP Folks logo is 99px, not
   ~140px; the label still does not fit.)

   "Sign in" IS NOT MOVED: it fits at 360px and above, and the tool's own
   signed-out bar keeps it visible; the Guide should match. (At 320px it is
   17px over, as it was in 1.0.2 -- not fixed here.)

   THE MENU BUTTON'S MARGIN. Both .navtoggle and .userbox.guest push to the
   right with margin-left:auto, which splits the free space and floats the
   menu button mid-bar -- the fault ui.py's own comments describe. With the
   account button gone, that would be all there is to see, so the userbox
   gives up its auto margin here and the menu button and search sit together
   at the right. The signed-out bar kept 1.0.2's layout until 1.0.4 (s48),
   which gives it the same fix in the bar's own rules (the 760px block and
   .compact). The two .ipf-in rules below are now redundant and kept.

   Specificity: .appbar.ipf-in .nav .ipf-navacct (0,4,0) outweighs the bar's
   .appbar .nav a (0,2,1) and the compact rules' .appbar.compact
   .nav:not(.always) a (0,4,1 -- only above 760px, where this is hidden).

   THE SAME AT 761-763px, where the longer label makes the bar fold its links
   into the menu (MENU_JS's .compact) while the button stays in the bar:
   measured, 1.0.2 never folded there, so without this line 1.0.3 would
   float the menu button mid-bar in that band. */
.appbar.compact.ipf-in .userbox.guest{margin-left:0}
.appbar .nav .ipf-navacct{display:none}
@media(max-width:760px){
  .appbar.ipf-in .userbox #ipf-account{display:none}
  .appbar.ipf-in .userbox.guest{margin-left:0}
  .appbar.ipf-in .nav .ipf-navacct{display:flex;align-items:center;
    justify-content:center;margin-top:8px;height:44px;min-height:44px;
    padding:0 16px;border-radius:99px;font-size:15px;font-weight:600;
    background:var(--panel);color:var(--indigo);border:1.5px solid var(--indigo);
    box-shadow:none;text-decoration:none}
  .appbar.ipf-in .nav .ipf-navacct:hover{background:var(--indigo-tint);
    color:var(--indigo-dk)}
}
