/* Shared base styles for every JustSimple page (Homepage, Dashboard, ...).
   Served from /static/base.css, loaded by base.html before any
   page-specific stylesheet. Only things every page needs live here
   (reset, page background, the .content wrapper, the shared hero/topbar
   title) -- anything specific to one page belongs in that page's own
   stylesheet instead.

   DESIGN-CONSISTENCY PASS (see chat): h1/topbar sizing, spacing, and the
   .content gutters below are now fixed here on purpose so every page --
   in this dashboard AND every other app that links this same file --
   renders the same title size, the same top/bottom spacing around it,
   and the same 5%/5% left-right gutter, instead of drifting per page.
   Do not redeclare .hero-title/.topbar/.content in a page's own
   stylesheet just to nudge spacing -- fix it here instead so every page
   stays in sync.

   Colors/spacing that are shared with the sidebar (--ink, --muted,
   --line, --accent, --brand-red) already come from sidebar.css's :root
   -- no need to redeclare them here, CSS custom properties on :root
   apply document-wide regardless of which stylesheet declared them. */

*{ box-sizing:border-box; }
html, body{ margin:0; padding:0; }

body{
  /* STEP 1 (Polaris fonts only): Inter first, system fallback so pages
     still render offline if the Google Fonts <link> in base.html fails.
     14px/20px is the Polaris base rhythm (was 15px/1.55). */
  font-family:var(--font-family-sans,"Inter",-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif);
  color:var(--ink);
  min-height:100vh;
  /* Framed Shopify shell: pure-black page backdrop so the outline
     reads around the rail + white page card. */
  background-color:var(--frame-bg, #000000);
  padding:var(--frame-pad, 10px);
  box-sizing:border-box;
  /* Baseline type rhythm every page inherits unless a specific element
     overrides it -- keeps paragraph/label text the same size, spacing
     and line-height everywhere instead of every app picking its own. */
  font-size:var(--font-body);
  line-height:1.43;
  letter-spacing:0;
  /* Shopify/Polaris rendering: antialiased (not macOS subpixel) +
     Inter single-story "a" (cv11), the way the admin reference reads. */
  -webkit-font-smoothing:antialiased;
  -moz-osx-font-smoothing:grayscale;
  font-feature-settings:"cv11";
}

/* Standard content wrapper every page's main content sits inside.
   width:90% + margin:0 auto = a fixed 5% gutter on the left AND right
   on every page, regardless of that page's own content (form, table,
   text, whatever) -- max-width keeps it from stretching edge-to-edge
   unreadably wide on very large monitors, still centered either way.
   Fixed top/bottom padding too, so the gap above/below content doesn't
   vary page to page. Pages should NOT override width/margin/horizontal
   padding here -- only extend vertical padding if a page genuinely
   needs a different top/bottom rhythm. */
.content{
  width:90%;
  max-width:1200px;
  margin:0 auto;
  padding:0 0 64px;
}

/* Consistent "hero title -> first thing in content" gap, whether or not
   a page uses {% block page_subtitle %}. That gap used to be split
   across two places: .topbar's own bottom padding
   (--stack-title-subtitle, 14px) plus .page-subtitle's own margin-bottom
   (--stack-subtitle-card, 28px). A page WITHOUT a subtitle (Rank
   Tracking, SEO Audit Tool, coming_soon, ...) only ever got the first
   14px, so it read as noticeably more cramped under the title than a
   page like Overview that has one -- see chat.
   Fix: .content itself always carries the second number as real
   padding-top, UNLESS .page-subtitle is literally the first thing
   inside .content -- in that case it already supplies its own
   margin-bottom for the exact same purpose, so we don't want to stack
   both and end up with double the gap above the subtitle text. */
.content:not(:has(> .page-subtitle:first-child)){
  padding-top: var(--stack-subtitle-card);
}

/* Shared hero header (title + red underline) used at the top of every
   top-level page's content -- Homepage, Dashboard, and any future page
   that wants the same branded header. Sits OUTSIDE .content (see
   base.html, which now renders this once for every page instead of
   each page's own template duplicating this markup -- see chat).

   Top padding is DERIVED from the same two tokens that build the
   bottom (h1 -> content) gap -- calc(--stack-title-subtitle +
   --stack-subtitle-card) -- instead of its own hardcoded number. Before
   this, top padding was a fixed 40px while the bottom gap was built
   from the two tokens separately; the two only looked "aligned" by
   coincidence at their original values (40 vs 14+28=42). The moment
   either token changed to fix the bottom gap, the top stopped matching
   ("一长一短" -- see chat). Deriving top from the same tokens means the
   two can never drift apart again, on any page, automatically. */
.topbar{
  padding:calc(var(--stack-title-subtitle) + var(--stack-subtitle-card)) 5% var(--stack-title-subtitle);
  /* Order #1078 frame: headers lead left-aligned (title + meta line),
     never centered -- actions sit at the row's right where a page has
     them (see .topbar-row in section 4). */
  text-align:left;
}

.hero-title{
  color:var(--ink);
  font-family:var(--font-family-sans,"Inter",-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif);
  font-size:var(--font-hero);
  font-weight:var(--weight-hero);
  line-height:1.4;
  letter-spacing:-0.01em;
  margin:0;
  text-align:left;
}

/* Red underline retired site-wide per design-consistency pass -- kept
   as display:none (rather than deleted) so any page/app that still has
   the old <svg class="hero-underline"> markup in its own template
   (not yet migrated to the shared base.html hero) also stops showing
   it, from this one shared file, without needing every app updated
   first. */
.hero-underline{ display:none; }

/* .hero-logo is retired -- the logo now lives only in the sidebar (see
   sidebar.js/.css). Not redeclared here anymore; if an older page
   template still has a <div class="hero-logo"><img></div> left in it,
   the image will just render unstyled instead of disappearing --
   update that template to drop the markup when you get to it. */

/* Shared "?" help icon + tooltip -- DESIGN-CONSISTENCY PASS. Several
   apps show a small "?" next to a label/metric with an explanation on
   hover; each one used to have its own copy of this with its own
   circle size/font-size/alignment. One definition here so every app
   just reuses this markup instead of redeclaring it:

     <span class="jsp-help">?<span class="jsp-help-tip">Explanation
     text goes here.</span></span>

   The tip is centered under the "?" and its text is justified so a
   multi-line explanation lines up on both edges instead of ragging. */
.jsp-help{
  position:relative;
  display:inline-flex; align-items:center; justify-content:center;
  width:16px; height:16px; flex:none;
  border-radius:50%;
  background:rgba(0,0,0,.08); color:var(--muted);
  font-size:0.68rem; font-weight:700; line-height:1;
  cursor:help;
}
.jsp-help-tip{
  display:none;
  position:absolute; bottom:calc(100% + 8px); left:50%;
  transform:translateX(-50%);
  width:220px;
  background:var(--ink); color:#fff;
  font-size:var(--font-caption); font-weight:500; line-height:1.45;
  text-align:justify; text-align-last:left;
  padding:10px 12px;
  border-radius:8px;
  box-shadow:0 8px 20px rgba(18,21,28,.18);
  /* Was z-index:20 -- the shared topbar (.jsp-topbar, see sidebar.css)
     sits at z-index:1100 and is position:fixed at the very top of the
     page, so any tooltip that pops up near the top of a page (e.g. a
     table header's "?" hint) rendered BEHIND it instead of over it.
     Bumped above the topbar (and its 1200 services-dropdown) but still
     below the 2000 modal overlays, so tooltips are never hidden by
     chrome that sits above the page content. */
  z-index:1300;
  /* Reset typography that could otherwise leak in from whatever element
     .jsp-help sits inside -- most notably a table <th> (uppercase,
     letter-spacing, white-space:nowrap for the header label itself).
     Without this, the tip inherits all three: text renders ALL CAPS,
     doesn't wrap, and overflows its 220px box instead of staying
     justified inside it. Every property the tooltip actually needs
     (font-size/weight/line-height/text-align) is already set explicitly
     above -- these three just weren't, until now. */
  text-transform:none;
  letter-spacing:normal;
  white-space:normal;
}
.jsp-help:hover .jsp-help-tip,
.jsp-help:focus .jsp-help-tip{ display:block; }

/* Credit-cost icon -- same hover/focus tooltip mechanics as .jsp-help
   above (reuses .jsp-help-tip as-is), just swapping the "?" glyph for
   a small coin icon and an accent tint, so a Search/Run button can
   show "this run costs N credits" on hover. Server-rendered with the
   `hidden` utility class already applied (see index.html templates) --
   an app's own page JS is what removes `hidden`, and only after
   window.JSPSidebar.checkCredits() confirms status.loggedIn, since
   credits only exist for logged-in members; a signed-out visitor
   should never see this icon at all. */
.jsp-credit-help{
  background:rgba(17,85,204,.1); color:var(--accent);
}
.jsp-credit-help svg{ width:10px; height:10px; display:block; }

/* Row-end variant -- for pairing the icon with an existing line of
   text (a hint/instruction paragraph) so it rides the end of that
   same line instead of adding a new line of its own. Needs the shared
   parent to be display:flex (each app's own CSS, scoped to that one
   row) -- margin-left:auto then pushes just the icon to the row's far
   right, leaving the text itself left-aligned and unaffected when the
   icon is hidden (logged-out visitor). */
.jsp-credit-help--row-end{ margin-left:auto; flex:none; }

/* Shared flashed-message banner -- DESIGN-CONSISTENCY PASS. Both
   rank-tracking and competitor-analysis's own per-app base.html had
   hand-copied an identical .flash rule (same colors, same padding) for
   Flask's get_flashed_messages(). One definition here now; any app's
   base.html can drop its local copy and just use this. */
.flash{
  background:#fff3cd; border:1px solid #ffe69c; border-radius:var(--radius-sm);
  padding:10px 14px; margin-bottom:16px; font-size:var(--font-body);
}

/* Shared "export" pill button -- DESIGN-CONSISTENCY PASS. Small
   outlined accent-colored button with an optional leading icon
   (<svg> sized via the rule below), used next to a report/chart
   section to trigger a download (PDF, CSV, image, whatever). Backlink
   and Overview each had their own slightly-different local copy of
   this before switching over -- this is the one canonical version new
   usage should reach for. An app is still free to keep a local
   override with a MORE specific selector if it genuinely needs a
   different look in one place, but shouldn't hand-roll a byte-for-byte
   copy of this again -- change it here so every app that just uses
   class="export-btn" moves together.
   NOTE: local .export-btn definitions in backlink.css / overview.css
   are unchanged and still take precedence there (same specificity,
   loaded after this file) -- not touched here to avoid any visual
   regression on pages that were already tuned against those. New
   pages (like seo_performance_report) should just use this shared
   one instead of adding their own copy. */
.export-btn{
  display:inline-flex; align-items:center; gap:6px; background:#fff; color:var(--accent);
  border:1px solid var(--accent); border-radius:7px; padding:8px 16px; font-size:var(--font-btn);
  font-weight:700; cursor:pointer; white-space:nowrap;
}
.export-btn:hover{ background:#eef3fc; }
.export-btn svg{ width:13px; height:13px; flex-shrink:0; }

/* Shared filter/select dropdown -- DESIGN-CONSISTENCY PASS. Opt-in via
   class (rather than styling the bare <select> element) so it doesn't
   silently change the look of every plain <select> already on the
   site -- only elements explicitly given class="jsp-select" pick this
   up. White background, --accent-tinted border, custom caret, so a
   report's date-range/filter dropdown reads as part of the same
   design system as its cards/buttons instead of the browser's raw
   default control. */
.jsp-select{
  padding:9px 32px 9px 14px; border:1px solid var(--accent); border-radius:var(--radius-sm);
  font-size:var(--font-input); font-weight:600; color:var(--accent); background:#fff;
  appearance:none; -webkit-appearance:none; cursor:pointer;
  background-image:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='10' height='6'><path d='M0 0l5 6 5-6z' fill='%231155cc'/></svg>");
  background-repeat:no-repeat; background-position:right 12px center;
}
.jsp-select:hover{ background-color:#eef3fc; }
/* The rules above style the CLOSED control (the box itself) --
   without anything more specific, browsers reuse that same `color`
   for every <option> inside the open native listbox too, so every
   row in the popup rendered accent-blue instead of just the selected
   one. These two rules override that for the popup only: normal rows
   read as plain black-on-white, and only the option that's actually
   selected/highlighted keeps the accent color -- closed control still
   looks exactly the same as before. */
.jsp-select option{ color:var(--ink); background:#fff; font-weight:500; }
.jsp-select option:checked{ color:var(--accent); font-weight:700; }

/* Canonical white card surface -- DESIGN-CONSISTENCY PASS. Every app's
   result/tool page is built from one or more of these stacked in
   .content (result cards, form cards, table cards, ...). Radius,
   padding and shadow all come from the shared tokens in sidebar.css's
   :root, so a card in seo-audit and a card in the dashboard render with
   identical corners/spacing. Don't redeclare .card locally to tweak its
   radius or padding -- change the token instead so every app moves
   together. */
.card{
  background:#fff;
  border:1px solid var(--line);
  border-radius:var(--radius-card);
  padding:var(--space-card);
  margin-bottom:20px;
  box-shadow:var(--shadow-card);
}
/* First heading inside a card shouldn't add its own top gap on top of
   the card's own padding -- keeps every card's internal top spacing
   identical regardless of what heading level it starts with. */
/* STEP 1 (Polaris fonts only): unstyled card headings default to the
   Polaris section scale (16px/600 for h2, 14px/600 for h3/h4) so cards
   without their own title class still match. Per-app .*-section-title
   rules (1.35rem) still win where they exist -- same specificity,
   loaded after this file -- and will be migrated in a later step. */
.card h2{
  font-family:var(--font-family-sans,"Inter",-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif);
  font-size:var(--font-section);
  font-weight:var(--weight-heading);
  line-height:1.5;
  letter-spacing:-0.01em;
  margin:0 0 12px;
}
.card h3, .card h4{
  font-family:var(--font-family-sans,"Inter",-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif);
  font-size:var(--font-body);
  font-weight:var(--weight-heading);
  line-height:1.43;
  margin:0 0 8px;
}
.card > h2:first-child, .card > h3:first-child, .card > h4:first-child{ margin-top:0; }

/* Shared subtitle line under the hero h1 -- used via base.html's
   {% block page_subtitle %}. Spacing to the h1 above and the first card
   below both come from the same tokens the topbar/hero-title use, so
   this reads identically on every page that has one. */
.page-subtitle{
  color:var(--muted);
  font-size:var(--font-body);
  line-height:1.43;
  margin:0 0 var(--stack-subtitle-card);
  text-align:left;
}

/* Small set of generic spacing/alignment utilities every app tends to
   need somewhere -- defined once here instead of every app's local
   stylesheet redeclaring its own .mb-8/.mt-10/etc with slightly
   different values. Keep this list short: anything domain-specific
   (e.g. a keyword-table column width) belongs in that app's own CSS,
   not here. */
.mb-8{ margin-bottom:8px; }
.mb-20{ margin-bottom:20px; }
.mt-8{ margin-top:8px; }
.mt-10{ margin-top:10px; }
.mt-20{ margin-top:20px; }
.m-0{ margin:0; }
.text-center{ text-align:center; }

/* Shared "optional controls row" pattern -- DESIGN-CONSISTENCY PASS.
   Several apps place a row of conditionally-rendered controls (project
   switcher, edit link, last-updated stamp, etc.) directly under the
   shared hero, e.g. rank-tracking's rt-header. Before that page's first
   project exists, none of those controls render, but the row itself
   was still taking up its own margin-bottom -- combined with .content's
   padding-top below (see the subtitle/no-subtitle rule above) AND that
   page's own ad-hoc inline margin-top on the next card, the same
   hero-to-first-card gap was being paid for three times over.

   .content's padding-top rule above is the ONE place that owns the
   hero -> first-card gap for every page, subtitle or not. A row like
   this should never add its own extra spacing on top of that.

   CONVENTION (not a CSS class -- there isn't a reliable CSS one):
   don't try to detect "this row has nothing in it" with :empty. Jinja
   renders whitespace/newlines between {% if %} blocks as real text
   nodes even when every condition is false, so the element is never
   truly DOM-empty and :empty silently never matches (this is exactly
   what happened to rt-header). Instead, wrap the ENTIRE row in the
   same condition that decides whether it has anything to show, e.g.:

     {% if projects or project %}
     <div class="rt-header"> ... </div>
     {% endif %}

   No element in the DOM at all = no margin left behind, full stop --
   more reliable than asking CSS to detect emptiness after the fact.
   Any always-present-but-invisible helper (a display:none tooltip
   host, etc.) that must survive regardless should live OUTSIDE this
   conditional, as a sibling, not inside the optional row. */

/* ---------------------------------------------------------------------
   Shared input-validation error (see input-validation.js).
   ONE look for every keyword / domain / URL box in every tool: red text,
   same size, always directly under the input box. Change it here only.
   --------------------------------------------------------------------- */
.jsp-field-error{
  display:block; width:100%; flex:0 0 100%;
  margin:6px 0 0; padding:0;
  color:#c0392b; font-size:var(--font-caption); font-weight:400; line-height:1.4;
  text-align:left; text-transform:none; letter-spacing:normal;
}
.jsp-field-error[hidden]{ display:none !important; }
.jsp-invalid{ border-color:#c0392b !important; }
.cr-search-row > .jsp-field-error{ margin-top:-8px; }
.bo-row > .jsp-field-error{ margin-top:-8px; }
.audit-form > .jsp-field-error{ margin-top:-4px; }
.jsp-field-error:empty{ display:none; }
