/* Self-hosted so no font request ever leaves the browser. Only 400 and
   600 exist: the only weights used anywhere on the site. Same files
   Haven uses (IBM Plex Mono is open-licensed, redistribution is fine). */
@font-face{
  font-family:'IBM Plex Mono';
  font-style:normal;
  font-weight:400;
  font-display:swap;
  src:url('fonts/ibmplexmono-400.woff2') format('woff2');
}
@font-face{
  font-family:'IBM Plex Mono';
  font-style:normal;
  font-weight:600;
  font-display:swap;
  src:url('fonts/ibmplexmono-600.woff2') format('woff2');
}

:root{
  color-scheme: light;
  --bg:#FAFCF7;
  --text-color:#101312;
  --text-muted:#4B5650;
  --border-color:#111513;
  --border-color-rgb:17,21,19;
  --border-default:2px solid var(--border-color);
  --panel-bg:#FFFFFF;
  /* The one accent hue used everywhere: alligator green. Soft/vivid two-state
     like a button rest/hover pair, plus a darker text-safe shade for anything
     sitting on a light-green background (badges, active states). */
  --accent:#3FAE5C;
  --accent-rgb:63,174,92;
  --accent-soft:#DCF3E1;
  --accent-vivid:#2E8C48;
  --accent-text:#1D5C31;
  /* --accent itself only measures 2.83:1 against white: well under WCAG
     AA's 4.5:1 for text (or even the 3:1 non-text-contrast minimum for an
     icon like .cat-icon's). Anywhere white text or a white icon sits on a
     solid green fill (primary buttons, active mode-btn, category icons,
     the checked checkbox) uses this darker shade instead, which clears
     4.5:1 (5.11:1, verified). --accent itself stays the lighter "light
     green" brand color everywhere else: borders, the mascot, badges with
     dark text on top: where no contrast problem exists. */
  --accent-strong:#2A7D40;
  --radius:10px;
  --shadow-pop:4px 4px 0 rgba(var(--border-color-rgb),1);
  --shadow-pop-sm:2px 2px 0 rgba(var(--border-color-rgb),1);
  --shadow-pop-accent:4px 4px 0 var(--accent);
  --font-mono:'IBM Plex Mono',monospace;
  --font-size-base:0.9375rem;
  --font-size-small:0.875rem;
  --line-height:1.5;
  --content-width:1100px;
  --transition-hover:transform .1s ease, box-shadow .1s ease;
  --hover-lift:translate(-2px,-2px);
}
*{box-sizing:border-box;}
/* Every hover-lift transition site-wide (buttons, mode-btn, dropzone,
   checkbox, range thumb, tool-card, category-jump, related-link) reads
   this one token instead of its own transition rule: redefining it here
   turns all 9 usages off at once for users who've asked for less motion,
   without repeating that whole selector list. */
@media (prefers-reduced-motion: reduce){
  :root{ --transition-hover:none; }
}
/* Removes the ~300ms double-tap-to-zoom delay mobile browsers add to any
   tap target by default: doesn't affect pinch-zoom (that's a page-level
   viewport setting, untouched here), just per-element tap responsiveness. */
html{touch-action:manipulation;-webkit-tap-highlight-color:transparent;}
/* Hides the native scrollbar so the page can't reflow narrower when a
   scrollbar appears (that reflow was squishing the header's zigzag
   divider: same fix Haven uses for its own wavy header edge).
   .scroll-indicator below replaces the lost scroll cue with a custom
   overlay that never occupies layout space. */
html{
  scrollbar-width:none; /* Firefox */
  -ms-overflow-style:none; /* legacy Edge/IE */
}
html::-webkit-scrollbar{ /* Chrome/Edge/Safari */
  width:0;
  height:0;
  background:transparent;
}
/* Custom scroll-position cue, replacing the hidden native scrollbar.
   Fixed positioning keeps it out of layout entirely. Height/top/
   visibility are driven by initScrollIndicator in shell.js.
   --accent-strong (not --border-color, unlike Haven's neutral-ink
   version) so the cue reads as the site's own alligator green. */
.scroll-indicator{
  position:fixed;
  top:0;
  right:3px;
  width:5px;
  border-radius:var(--radius);
  background:var(--accent-strong);
  opacity:0;
  transition:opacity .25s ease;
  pointer-events:none;
  z-index:1000;
}
.scroll-indicator.visible{opacity:1;}
@media (prefers-reduced-motion: reduce){
  .scroll-indicator{transition:none;}
}
html,body{margin:0;padding:0;}
/* Off-screen until keyboard-focused (shell.js injects this as the page's
   first focusable element on every page): standard skip-link pattern,
   not visible to sighted mouse users but the first thing a keyboard/screen
   reader user encounters. */
.skip-link{
  position:absolute;
  left:8px;top:-60px;
  background:var(--accent-strong);
  color:#fff;
  padding:10px 16px;
  border-radius:var(--radius);
  border:var(--border-default);
  font-family:var(--font-mono);
  font-weight:600;
  font-size:var(--font-size-small);
  text-decoration:none;
  z-index:1000;
  transition:top .15s ease;
}
.skip-link:focus{top:8px;}
@media (prefers-reduced-motion: reduce){
  .skip-link{transition:none;}
}
main:focus-visible{outline:none;}
body{
  /* Faint graph-paper grid: a math/calculator motif instead of Haven's
     gradient-blob background, fixed so it doesn't scroll with content. */
  background-image:
    linear-gradient(rgba(var(--accent-rgb),0.08) 1px, transparent 1px),
    linear-gradient(90deg, rgba(var(--accent-rgb),0.08) 1px, transparent 1px);
  background-size:28px 28px;
  background-attachment:fixed;
  background-color:var(--bg);
  color:var(--text-color);
  font-family:var(--font-mono);
  font-weight:400;
  line-height:var(--line-height);
  min-height:100vh;
}
::selection{background:var(--accent-strong);color:#fff;}
::-moz-selection{background:var(--accent-strong);color:#fff;}
a{color:var(--accent-text);text-decoration:underline;text-decoration-color:rgba(var(--accent-rgb),0.5);text-underline-offset:3px;}
a:hover, a:focus-visible{text-decoration-color:var(--accent-text);}
button, select, input{font-family:inherit;}
a:focus-visible,
.btn:focus-visible,
.tool-card:focus-visible,
.mode-btn:focus-visible,
.faq-item summary:focus-visible{
  outline:3px solid var(--accent-vivid);
  outline-offset:2px;
}

/* ---------- Header ---------- */
header.shell-header{
  background:var(--panel-bg);
  border-bottom:var(--border-default);
  position:sticky;
  top:0;
  z-index:10;
  padding:16px 32px;
  display:flex;
  align-items:center;
  justify-content:space-between;
  flex-wrap:wrap;
  gap:12px;
}
/* Zigzag "teeth" divider: the site's signature motif, an alligator-jaw
   callback replacing the smooth wavy line a different site (Haven) uses.
   Tiled SVG triangle wave; color is hardcoded since custom properties
   can't be read inside a data-URI SVG. */
header.shell-header::after{
  content:'';
  position:absolute;
  left:0;
  right:0;
  top:100%;
  height:10px;
  background:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='20' height='10' viewBox='0 0 20 10'%3E%3Cpath d='M0 0 L10 10 L20 0 Z' fill='%23111513'/%3E%3C/svg%3E") top / 20px 10px repeat-x;
  pointer-events:none;
}
.wordmark{display:flex;align-items:center;gap:10px;}
.wordmark a{display:flex;align-items:center;gap:10px;color:inherit;text-decoration:none;}
.wordmark .mascot{display:block;width:38px;height:38px;flex-shrink:0;object-fit:contain;}
.wordmark .site-name{
  font-family:var(--font-mono);
  font-weight:600;
  font-size:1.2rem;
  color:var(--text-color);
}
.wordmark .site-name .accent-letters{color:var(--accent-vivid);}
.wordmark .tagline{
  font-family:var(--font-mono);
  font-size:var(--font-size-small);
  font-weight:400;
  color:var(--text-muted);
  padding-left:10px;
  border-left:var(--border-default);
}
@media (max-width:800px){
  .wordmark .tagline{display:none;}
}
.header-links{display:flex;gap:16px;font-size:var(--font-size-small);}

.calc-menu{position:relative;}
.calc-menu-trigger{
  display:inline-flex;align-items:center;gap:6px;
  background:none;border:none;cursor:pointer;
  /* padding, not just the text's own line height, so the real tap target
     clears WCAG 2.5.8's 24px minimum: the text alone only measured 18px tall. */
  padding:4px 2px;margin:-4px -2px;
  font-family:var(--font-mono);font-size:var(--font-size-small);font-weight:600;
  color:var(--accent-text);
  text-decoration:underline;text-decoration-color:rgba(var(--accent-rgb),0.5);text-underline-offset:3px;
}
.calc-menu-trigger:hover, .calc-menu-trigger:focus-visible{text-decoration-color:var(--accent-text);}
.calc-menu-trigger .chevron{width:14px;height:14px;transition:transform .15s ease;}
.calc-menu-trigger[aria-expanded="true"] .chevron{transform:rotate(180deg);}
@media (prefers-reduced-motion: reduce){
  .calc-menu-trigger .chevron{transition:none;}
}
/* left:0 is just the CSS fallback for the very first paint: shell.js's
   positionMenuPanel() always overrides it with an explicit pixel `left`
   once the menu opens, clamped so the panel never runs off either edge of
   the viewport regardless of where the trigger itself ends up sitting
   (the header can wrap the trigger to the left side of its own row on
   narrow screens, which is what broke the old `right:0` assumption: see
   CLAUDE.md). max-width guarantees the panel itself is never wider than
   the viewport has room for, independent of that positioning. */
.calc-menu-panel{
  position:absolute;top:calc(100% + 14px);left:0;
  display:grid;grid-template-columns:repeat(2,190px);gap:18px 28px;
  background:var(--panel-bg);border:var(--border-default);border-radius:var(--radius);
  box-shadow:var(--shadow-pop);padding:18px;
  max-height:75vh;overflow-y:auto;overflow-x:hidden;overscroll-behavior:contain;
  max-width:calc(100vw - 16px);
  z-index:20;
}
.calc-menu-panel[hidden]{display:none;}
/* Setting overflow-y without overflow-x leaves overflow-x at its default
   `visible`, which the CSS spec then computes up to `auto` too (the two
   axes can't independently be visible/non-visible): that's what was
   drawing a horizontal scrollbar here despite the panel never actually
   overflowing sideways. overflow-x:hidden above closes that off.
   The vertical scrollbar itself also needs its own styling: this panel is
   a separate scroll container from <html>, so the page-wide scrollbar hiding
   further up this file (and its .scroll-indicator replacement, which is
   fixed-position and tied to document scroll) doesn't reach it: left alone,
   it shows the browser's native scrollbar instead of this site's own look.
   Styled to match .scroll-indicator's own accent-strong/rounded appearance
   (a thin colored bar, not the native OS chrome) rather than duplicating
   that fixed-position/JS-driven component, which is built specifically for
   whole-page scroll and isn't a fit for a small internal panel. */
.calc-menu-panel{
  scrollbar-width:thin;
  scrollbar-color:var(--accent-strong) transparent;
}
.calc-menu-panel::-webkit-scrollbar{width:6px;}
.calc-menu-panel::-webkit-scrollbar-track{background:transparent;}
.calc-menu-panel::-webkit-scrollbar-thumb{
  background:var(--accent-strong);
  border-radius:var(--radius);
}

/* Every tool's <textarea> (Word Counter, Text Case Converter, Duplicate Line
   Remover, Word Frequency Counter, Reverse Text, QR Code Generator) showed
   the browser's own scrollbar (complete with up/down arrow buttons)
   once typed text overflowed the box, plus a plain grey native resize grip
   in the corner. Same thin/accent-strong treatment as .calc-menu-panel's
   own scrollbar above, applied to every textarea site-wide via the bare
   element selector (each tool page styles its own textarea's border/padding
   independently, but none of them touch scrollbar/resizer, so this is safe
   to apply globally without colliding with any page-specific rule). */
textarea{
  scrollbar-width:thin;
  scrollbar-color:var(--accent-strong) transparent;
}
textarea::-webkit-scrollbar{width:8px;}
textarea::-webkit-scrollbar-track{background:transparent;}
textarea::-webkit-scrollbar-thumb{background:var(--accent-strong);border-radius:var(--radius);}
textarea::-webkit-scrollbar-button{display:none;height:0;width:0;}
/* The resize-handle glyph itself can't be recolored cross-browser, but
   WebKit/Blink's own resizer swatch background can at least be tinted to
   match the field instead of the native default grey. */
textarea::-webkit-resizer{background-color:var(--panel-bg);}

/* Live search/filter box at the top of the dropdown: added once the site
   passed 50+ tools, when scrolling through all 9 category groups to find one
   specific calculator started to feel tedious. Spans both grid columns
   (grid-column:1/-1) since .calc-menu-panel itself is a 2-column grid. */
.calc-menu-search{
  grid-column:1/-1;
  width:100%;
  font-family:var(--font-mono);
  font-size:var(--font-size-small);
  padding:8px 10px;
  border:var(--border-default);
  border-radius:var(--radius);
  background:var(--panel-bg);
  color:var(--text-color);
  transition:var(--transition-hover);
}
.calc-menu-search:hover, .calc-menu-search:focus-visible{
  border-color:var(--accent-vivid);
  box-shadow:var(--shadow-pop-accent);
}
.calc-menu-search:focus-visible{outline:none;}
.calc-menu-empty{grid-column:1/-1;font-size:var(--font-size-small);color:var(--text-muted);margin:0;}
.calc-menu-group[hidden]{display:none;}
.calc-menu-group a[hidden]{display:none;}
.calc-menu-group-label{
  display:flex;align-items:center;gap:7px;
  font-size:var(--font-size-small);font-weight:600;color:var(--text-color);
  margin:0 0 8px;
}
.calc-menu-group-label svg{width:15px;height:15px;color:var(--accent-strong);flex-shrink:0;}
/* padding:7px 4px (not the 4px 0 tried first) so the real tap target clears
   WCAG 2.5.8's 24px minimum: font-size-small's own line height alone
   landed a couple px short. */
.calc-menu-group a{
  display:block;padding:7px 4px;font-size:var(--font-size-small);color:var(--text-muted);text-decoration:none;
}
.calc-menu-group a:hover, .calc-menu-group a:focus-visible{color:var(--accent-text);text-decoration:underline;}
@media (max-width:640px){
  /* An explicit width, not just max-width: an absolutely-positioned box
     with only `left` set (no `right`) sizes itself by CSS shrink-to-fit,
     and a flexible `1fr` grid track shrinks to its content's own minimum
     width under that algorithm instead of filling the available space
     (measured as low as 146px in testing, cutting off longer tool names).
     A concrete width sidesteps that ambiguity entirely. */
  .calc-menu-panel{
    grid-template-columns:1fr;
    width:calc(100vw - 16px);
    max-width:320px;
  }
}

/* ---------- Layout ---------- */
main{
  max-width:var(--content-width);
  margin:0 auto;
  padding:36px 24px 0;
}
main:not(.tool-main) > * + *{margin-top:36px;}
/* Grid, not flex: breadcrumb and the title block are full-width rows
   (.full-width, grid-column:1/-1) above the two real columns, so
   tool-primary and tool-side both start on the same grid row and align
   at the same top edge. Letting the title block live only inside
   tool-primary (an earlier version) made the sidebar's result panel
   float noticeably higher than the input panel beside it: a real
   layout bug, not just a spacing preference. One shared `gap` handles
   every row AND column gap, so there's no separate margin value to keep
   in sync with it. */
main.tool-main{
  display:grid;
  grid-template-columns:1fr 320px;
  gap:28px;
  align-items:start;
}
main.tool-main .full-width{grid-column:1 / -1;}
main.tool-main .tool-primary{display:flex;flex-direction:column;gap:20px;min-width:0;}
/* Sticky, not just align-items:start: when the left column (inputs +
   "How this works") runs much longer than the right column (result +
   related tools), a plain static sidebar stalls near the top of a tall
   grid row and leaves a large dead gap of page background below it before
   the next section starts. Sticking it under the header instead means it
   travels down the page with the user's scroll position, so there's
   always something next to whatever part of the left column they're
   reading, and no empty gap reads as "missing content." top matches the
   header's own height (~74px) plus its zigzag edge (10px) plus a small
   buffer. Turned off below 820px, where the columns stack and stickiness
   would just pin the sidebar oddly above the (now full-width) primary
   column. */
main.tool-main .tool-side{display:flex;flex-direction:column;gap:20px;min-width:0;position:sticky;top:calc(var(--header-h, 74px) + 22px);align-self:start;}
@media (max-width:820px){
  main.tool-main{grid-template-columns:1fr;}
  main.tool-main .tool-side{position:static;}
  /* display:contents unwraps tool-primary/tool-side into main's own grid so
     their sections can be individually reordered: stacked mobile order
     otherwise ran fields, "how this works", THEN the result, which reads
     backwards (the result panel is what a user actually came to see right
     after filling in the fields). Related tools stays last either way. */
  main.tool-main .tool-primary, main.tool-main .tool-side{display:contents;}
  main.tool-main .tool-primary > .panel{order:1;}
  main.tool-main .tool-side > .result-panel{order:2;}
  main.tool-main .tool-primary > .about-section{order:3;}
  main.tool-main .tool-side > .related-tools{order:4;}
}

.breadcrumb{
  font-size:var(--font-size-small);
  color:var(--text-muted);
  display:flex;
  gap:6px;
  flex-wrap:wrap;
}
/* padding, not just the text's own line height, so the real tap target
   clears WCAG 2.5.8's 24px minimum: the text alone only measured 21px tall. */
.breadcrumb a{display:inline-block;color:var(--text-muted);padding:2px;margin:-2px;}
.breadcrumb .sep{color:var(--text-muted);}
.breadcrumb .current{color:var(--text-color);}

.tool-title{
  font-family:var(--font-mono);
  font-weight:600;
  font-size:1.4rem;
  color:var(--text-color);
  margin:0;
  text-wrap:balance;
}
.tool-subtitle{
  font-size:var(--font-size-base);
  color:var(--text-muted);
  margin:6px 0 0;
}

/* ---------- Panels ---------- */
/* Consistent vertical rhythm between whatever a tool page stacks inside a
   panel (a fieldset, a .field-grid, a unit-toggle wrapper div, another
   .field-grid nested inside that wrapper...): these blocks used to only
   get a gap when a page remembered its own inline `style="margin-top:16px"`,
   which several tools missed in different spots (reported by the user as
   "spacing issues between buttons/fields", confirmed across several
   US/Metric-toggle tools: e.g. Calorie's height field-grid nested inside
   #usFields had no gap above it, Ideal Weight's #usFields wrapper had none
   at all). `* + *` only matches an element with a preceding sibling, so the
   panel's own top padding is never doubled up on the first child: same
   "no first-child exemption needed" shape as `main`'s own `* + *` rule
   further down this file. Makes the scattered inline margin-top styles on
   individual tool pages redundant (harmless, same value) rather than
   required going forward. */
.panel > * + *{margin-top:16px;}
.panel{
  background:var(--panel-bg);
  border:var(--border-default);
  border-radius:var(--radius);
  box-shadow:var(--shadow-pop);
  padding:22px;
}
fieldset{border:none;margin:0;padding:0;min-width:0;}
.panel h2, .panel legend{
  font-family:var(--font-mono);
  font-weight:600;
  font-size:var(--font-size-base);
  color:var(--text-color);
  margin:0 0 4px;
  padding:0;
}
.field-grid{display:grid;grid-template-columns:1fr 1fr;gap:16px;}
@media (max-width:520px){.field-grid{grid-template-columns:1fr;}}
.field{display:flex;flex-direction:column;gap:6px;margin-top:16px;}
.field:first-child{margin-top:0;}
.field-grid .field{margin-top:0;}
.field label{
  font-family:var(--font-mono);
  font-size:var(--font-size-small);
  font-weight:600;
  color:var(--text-color);
}
.field .hint{font-size:var(--font-size-small);color:var(--text-muted);font-weight:400;}
/* .list-row's own select/text/number inputs (GPA's course rows) share this
   exact recipe: they're not wrapped in a .field, but they're the same
   kind of boxed form control, and without this they fell back to bare
   unstyled browser defaults (including no visible focus-visible ring),
   a real gap only found once specifically auditing focus states. */
.field select,
.field input[type=number],
.field input[type=text],
.field input[type=date],
.field input[type=time],
.list-row select,
.list-row input[type=text],
.list-row input[type=number]{
  background:var(--panel-bg);
  color:var(--text-color);
  border:var(--border-default);
  border-radius:var(--radius);
  padding:10px 12px;
  font-family:var(--font-mono);
  font-weight:400;
  font-size:var(--font-size-base);
  width:100%;
  min-width:0;
  transition:var(--transition-hover);
}
.field select:hover:not(:disabled), .field select:focus-visible:not(:disabled),
.field input:hover:not(:disabled), .field input:focus-visible:not(:disabled),
.list-row select:hover:not(:disabled), .list-row select:focus-visible:not(:disabled),
.list-row input:hover:not(:disabled), .list-row input:focus-visible:not(:disabled){
  border-color:var(--accent-vivid);
  transform:var(--hover-lift);
  box-shadow:var(--shadow-pop-accent);
}
/* This border-color/box-shadow change on focus is already a fully visible
   focus indicator on its own: these fields used to ALSO match the
   site-wide outline rule above, stacking a second, offset green ring on
   top of the border that had just turned the same green, which looked
   like a doubled/duplicated highlight (worst on number inputs, whose
   heavily rounded corners made the two concentric outlines obvious;
   reported by the user). Same fix already applied to the range slider
   thumb for the same reason. */
.field select:focus-visible, .field input:focus-visible{outline:none;}
.field select:disabled, .field input:disabled{opacity:0.45;cursor:not-allowed;}
.field input::placeholder, .list-row input::placeholder{color:var(--text-muted);opacity:0.7;}
/* Native number-input spin arrows were never actually hidden anywhere on
   the site: every plain (non-stepper) number field showed the browser's
   own up/down arrows on hover/focus, which don't respect this site's
   border/radius and read as visually broken next to it (reported by the
   user on Coin Flip's "Number of flips" field, but the gap was site-wide,
   not specific to that one page). Hidden the same way the checkbox and
   dropdown-select arrow already are: the native control can't be
   restyled, only removed, matching every other custom-control decision on
   this site. Typing a value or using the keyboard's own arrow keys still
   works; tools that specifically want a clickable +/- already have their
   own `.stepper` buttons for that. */
.field input[type=number]::-webkit-inner-spin-button,
.field input[type=number]::-webkit-outer-spin-button,
.list-row input[type=number]::-webkit-inner-spin-button,
.list-row input[type=number]::-webkit-outer-spin-button{
  -webkit-appearance:none;
  margin:0;
}
.field input[type=number],
.list-row input[type=number]{
  -moz-appearance:textfield;
}
.field-unit{position:relative;}
.field-unit input{padding-right:40px;}
.field-unit .unit-suffix{
  position:absolute;right:12px;top:50%;transform:translateY(-50%);
  font-size:var(--font-size-small);color:var(--text-muted);pointer-events:none;
}

/* Every tool with a free-text textarea (Word Counter, Duplicate Line
   Remover, Reverse Text, Word Frequency Counter) had this exact recipe
   copy-pasted into its own local <style> block: consolidated here since
   textarea isn't covered by the .field input[type=...] list above. Includes
   the same hover/focus pop those other inputs get, which the copy-pasted
   versions had all been missing. */
.text-area{
  width:100%;
  min-width:0;
  font-family:var(--font-mono);
  font-size:var(--font-size-base);
  padding:10px 12px;
  border:var(--border-default);
  border-radius:var(--radius);
  background:var(--panel-bg);
  color:var(--text-color);
  resize:vertical;
  transition:var(--transition-hover);
}
.text-area:hover, .text-area:focus-visible{
  border-color:var(--accent-vivid);
  box-shadow:var(--shadow-pop-accent);
}
.text-area:focus-visible{outline:none;}

/* Password Generator's length field: a +/- pair flanking the number input,
   for a clickable (not just typed) way to adjust it. Generic here rather
   than scoped to that one tool, in case a future field needs the same
   pattern. */
/* align-items:stretch (not center) so .stepper-btn's height always matches
   whatever height .stepper-input actually renders at: avoids hardcoding a
   pixel height here that could drift out of sync with the shared field
   recipe's own padding/font-size/border if those ever change. */
.stepper{display:flex;align-items:stretch;gap:8px;}
.stepper-input{flex:1;min-width:0;}
.stepper-btn{width:36px;padding:0;flex-shrink:0;display:flex;align-items:center;justify-content:center;font-size:1.1rem;line-height:1;}

/* ---------- Image tools (Compressor/Resizer/Converter) ---------- */
/* Dashed border (the one dashed border on the site) marks this as a drop
   target, distinct from every other solid-bordered panel/card/button. */
.dropzone{
  border:2px dashed var(--border-color);
  border-radius:var(--radius);
  background:var(--panel-bg);
  padding:36px 20px;
  text-align:center;
  cursor:pointer;
  transition:var(--transition-hover);
}
.dropzone:hover, .dropzone:focus-visible, .dropzone.dragover{
  border-color:var(--accent-vivid);
  background:var(--accent-soft);
}
.dropzone input[type=file]{display:none;}
.dropzone .drop-title{font-family:var(--font-mono);font-weight:600;font-size:var(--font-size-base);color:var(--text-color);margin:0 0 6px;}
.dropzone .hint{font-size:var(--font-size-small);color:var(--text-muted);margin:0;}
.file-name{font-size:var(--font-size-small);color:var(--text-muted);margin:10px 0 0;word-break:break-all;}
#canvasWrap{
  display:none;
  text-align:center;
  padding:16px;
  background:var(--panel-bg);
  border:var(--border-default);
  border-radius:var(--radius);
  margin-top:16px;
}
#canvasWrap.active{display:block;}
#canvasWrap canvas{max-width:100%;height:auto;border-radius:calc(var(--radius) - 2px);}

/* 24x24, not the visually-tighter 18x18 tried first: WCAG 2.5.8 (Target
   Size, Minimum) requires at least 24x24 CSS px for a custom control like
   this, and box-sizing:border-box (set globally above) means the width/
   height here already include the border, so this is the true click/tap
   target size, not just the visible square's inner content. */
input[type=checkbox]{
  appearance:none;
  -webkit-appearance:none;
  width:24px;
  height:24px;
  flex-shrink:0;
  margin:0;
  border:var(--border-default);
  border-radius:5px;
  background:var(--panel-bg);
  cursor:pointer;
  position:relative;
  transition:var(--transition-hover);
}
input[type=checkbox]:hover:not(:disabled), input[type=checkbox]:focus-visible:not(:disabled){border-color:var(--accent-vivid);transform:var(--hover-lift);}
input[type=checkbox]:checked{background:var(--accent-strong);border-color:var(--border-color);}
input[type=checkbox]:disabled{opacity:0.45;cursor:not-allowed;}
input[type=checkbox]:checked::after{
  content:'';
  position:absolute;
  left:7px;top:2px;
  width:5px;height:11px;
  border:solid #fff;
  border-width:0 2px 2px 0;
  transform:rotate(45deg);
}
@media (forced-colors: active){
  input[type=checkbox]:checked{background:Highlight;border-color:Highlight;}
  input[type=checkbox]:checked::after{border-color:HighlightText;}
}

/* Missing entirely until the image tools' quality sliders needed it.
   Every other input type on the site (number, text, date, select, color,
   checkbox) already has a custom recipe; native range styling can't be
   tweaked directly, only rebuilt, same reasoning as the checkbox above.
   Thumb is 24x24 (not visually smaller) to clear the same WCAG 2.5.8
   minimum every other custom control on the site is held to. */
input[type=range]{
  -webkit-appearance:none;
  appearance:none;
  width:100%;
  height:8px;
  background:var(--panel-bg);
  border:var(--border-default);
  border-radius:var(--radius);
  cursor:pointer;
  margin:6px 0;
}
input[type=range]::-webkit-slider-thumb{
  -webkit-appearance:none;
  width:24px;height:24px;
  border-radius:var(--radius);
  background:var(--accent-strong);
  border:var(--border-default);
  cursor:pointer;
  transition:var(--transition-hover);
}
input[type=range]::-moz-range-thumb{
  width:24px;height:24px;
  border-radius:var(--radius);
  background:var(--accent-strong);
  border:var(--border-default);
  cursor:pointer;
  transition:var(--transition-hover);
}
input[type=range]:hover:not(:disabled)::-webkit-slider-thumb,
input[type=range]:focus-visible:not(:disabled)::-webkit-slider-thumb{transform:var(--hover-lift);box-shadow:var(--shadow-pop-sm);}
input[type=range]:hover:not(:disabled)::-moz-range-thumb,
input[type=range]:focus-visible:not(:disabled)::-moz-range-thumb{transform:var(--hover-lift);box-shadow:var(--shadow-pop-sm);}
input[type=range]:focus-visible{outline:none;}
input[type=range]:disabled{opacity:0.45;cursor:not-allowed;}
input[type=range]:disabled::-webkit-slider-thumb{cursor:not-allowed;}
input[type=range]:disabled::-moz-range-thumb{cursor:not-allowed;}

.actions{display:flex;flex-wrap:wrap;gap:10px;margin-top:20px;}
/* Guide pages' "try this calculator" CTA row: a centered pair of buttons
   closing out the page, unlike every tool page's single left-aligned
   Reset/Clear button sitting under its own left-aligned fields. Scoped to
   this modifier rather than changing .actions itself, since centering a
   lone Reset button under left-aligned form fields would look off. */
.actions.centered{justify-content:center;}
.btn{
  font-family:var(--font-mono);
  font-size:var(--font-size-base);
  font-weight:600;
  padding:11px 18px;
  border-radius:var(--radius);
  border:var(--border-default);
  background:var(--panel-bg);
  color:var(--text-color);
  cursor:pointer;
  transition:var(--transition-hover);
}
.btn:hover:not(:disabled), .btn:focus-visible:not(:disabled){
  transform:var(--hover-lift);
  box-shadow:var(--shadow-pop);
}
.btn:disabled{opacity:0.45;cursor:not-allowed;}
.btn.primary{background:var(--accent-strong);color:#fff;border-color:var(--border-color);}
.btn.primary:hover:not(:disabled), .btn.primary:focus-visible:not(:disabled){box-shadow:var(--shadow-pop);}
.btn.icon{padding:8px 10px;line-height:0;}
.btn.small{padding:6px 10px;font-size:var(--font-size-small);}

.mode-btn{
  display:flex;align-items:center;gap:8px;
  background:var(--panel-bg);
  border:var(--border-default);
  color:var(--text-color);
  font-family:var(--font-mono);
  font-weight:400;
  font-size:var(--font-size-small);
  padding:9px 12px;
  border-radius:var(--radius);
  cursor:pointer;
  transition:var(--transition-hover);
}
.mode-btn:hover:not(:disabled), .mode-btn:focus-visible:not(:disabled){transform:var(--hover-lift);box-shadow:var(--shadow-pop-accent);}
.mode-btn.active{background:var(--accent-strong);color:#fff;border-color:var(--border-color);}
.modes{display:flex;flex-wrap:wrap;gap:8px;}

/* ---------- Result panel ---------- */
.result-panel{
  background:var(--accent-soft);
  border:var(--border-default);
  border-radius:var(--radius);
  box-shadow:var(--shadow-pop);
  padding:22px;
}
.result-panel .result-label{
  font-size:var(--font-size-small);
  font-weight:600;
  color:var(--accent-text);
  margin:0 0 6px;
  letter-spacing:0.04em;
}
.result-panel .result-value{
  font-size:2rem;
  font-weight:600;
  color:var(--text-color);
  margin:0;
  line-height:1.2;
  word-break:break-word;
  font-variant-numeric:tabular-nums;
}
.result-panel .result-value.empty{color:var(--text-muted);font-size:var(--font-size-base);font-weight:400;}
.result-row{
  display:flex;justify-content:space-between;gap:10px;
  font-size:var(--font-size-small);
  padding:8px 0;
  border-top:1px solid rgba(var(--border-color-rgb),0.2);
}
.result-row:first-of-type{border-top:none;}
.result-row .label{color:var(--text-muted);}
.result-row .value{font-weight:600;color:var(--text-color);font-variant-numeric:tabular-nums;}

/* ---------- List rows (GPA course rows, merge-style file list) ---------- */
.row-list{display:flex;flex-direction:column;gap:8px;margin:10px 0 0;padding:0;list-style:none;}
.row-list:empty{margin-top:0;}
.list-row{
  display:grid;
  grid-template-columns:1fr 100px 90px 32px;
  gap:8px;
  align-items:center;
  border:var(--border-default);
  border-radius:var(--radius);
  padding:8px 10px;
  background:var(--panel-bg);
}
@media (max-width:520px){.list-row{grid-template-columns:1fr 1fr;}}
.list-row input, .list-row select{margin:0;}
/* padding:6px (not the 4px first tried) so the actual click/tap target
   clears WCAG's 24x24 CSS px minimum: the glyph itself is much smaller,
   but padding is part of a button's hit area, not just its ink. */
.list-row .remove-row{
  background:none;border:none;cursor:pointer;color:var(--text-muted);
  font-size:1.1rem;line-height:1;padding:6px;
  border-radius:4px;
}
.list-row .remove-row:hover{color:var(--accent-vivid);}
.list-row .remove-row:focus-visible{outline:3px solid var(--accent-vivid);outline-offset:1px;}

/* ---------- Homepage / category sections ---------- */
.hero{text-align:center;padding:20px 0 0;}
.hero .mascot-hero{display:block;margin:0 auto 16px;}
.hero .mascot-hero-img{display:block;width:170px;height:170px;margin:0 auto;object-fit:contain;}
.hero h1{
  font-family:var(--font-mono);
  font-weight:600;
  font-size:1.4rem;
  margin:0 auto 14px;
  max-width:920px;
  line-height:1.35;
  color:var(--text-color);
  text-wrap:balance;
}
.hero p{
  font-size:var(--font-size-base);
  color:var(--text-muted);
  max-width:680px;
  margin:0 auto;
}
.hero .updated{
  font-size:0.85rem;
  margin:10px auto 0;
}
.category-jump{
  display:flex;flex-wrap:wrap;gap:10px;justify-content:center;
}
/* .link-btn is the same pill link the homepage's category-jump nav uses,
   shared via this selector list rather than duplicated: guide pages' "try
   this calculator" CTAs reuse it too (see Guides section below), so both
   stay visually identical instead of drifting into two similar-but-not-quite
   the-same components. */
.category-jump a, .link-btn{
  display:inline-flex;align-items:center;gap:6px;
  border:var(--border-default);border-radius:var(--radius);
  padding:7px 14px;font-size:var(--font-size-small);font-weight:600;
  color:var(--text-color);background:var(--panel-bg);text-decoration:none;
  transition:var(--transition-hover);
}
/* Matches the same "pop" language every field/tool-card uses on hover and
   keyboard focus (border turns accent-vivid, colored shadow, slight lift).
   It used to instead invert to a solid green fill (mimicking .mode-btn.active's
   own toggle-button look), which read as a visually different kind of
   highlight than the rest of the site when reached by keyboard (reported by
   the user: pills/cards should "pop out like fields do"). */
.category-jump a:hover, .category-jump a:focus-visible,
.link-btn:hover, .link-btn:focus-visible{border-color:var(--accent-vivid);transform:var(--hover-lift);box-shadow:var(--shadow-pop-accent);}
.category-jump svg{width:16px;height:16px;flex-shrink:0;}

/* #categorySections (the wrapper these all live in) only gets ONE 36px
   margin-top from the `main:not(.tool-main) > * + *` rule above, since
   that rule only sees direct children of <main>: every .category-section
   inside the wrapper needs its own gap from the one before it, or they'd
   render back-to-back with zero space between them. Matches the site's
   standard 36px rhythm rather than inventing a smaller one. */
.category-section{scroll-margin-top:calc(var(--header-h, 74px) + 16px);}
.category-section + .category-section{margin-top:36px;}
.category-heading{display:flex;align-items:center;gap:10px;margin:0 0 14px;}
.category-heading .cat-icon{
  width:34px;height:34px;flex-shrink:0;
  display:flex;align-items:center;justify-content:center;
  background:var(--accent-strong);border:var(--border-default);border-radius:var(--radius);
}
.category-heading .cat-icon svg{width:19px;height:19px;color:#fff;}
.category-heading h2{
  font-family:var(--font-mono);font-weight:600;font-size:1.15rem;
  color:var(--text-color);margin:0;text-wrap:balance;
}
.category-heading p{margin:0;font-size:var(--font-size-small);color:var(--text-muted);}

.tool-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));gap:14px;}
.tool-card{
  display:flex;flex-direction:column;gap:4px;
  border:var(--border-default);border-radius:var(--radius);
  background:var(--panel-bg);padding:16px;color:inherit;text-decoration:none;
  transition:var(--transition-hover);
}
.tool-card:hover, .tool-card:focus-visible{box-shadow:var(--shadow-pop-accent);transform:var(--hover-lift);}
.tool-card h3{font-size:var(--font-size-base);font-weight:600;margin:0;color:var(--text-color);}
.tool-card p{font-size:var(--font-size-small);color:var(--text-muted);margin:0;}

.about-section{
  padding:22px;background:var(--panel-bg);border:var(--border-default);
  border-radius:var(--radius);box-shadow:var(--shadow-pop);
}
.about-section .about-label{font-weight:600;font-size:var(--font-size-base);margin:0 0 8px;color:var(--text-color);}
.about-section p{font-size:var(--font-size-small);color:var(--text-muted);margin:0 0 10px;}
.about-section p:last-child{margin-bottom:0;}
.about-section ul{margin:0;padding-left:20px;font-size:var(--font-size-small);color:var(--text-muted);}
.about-section li{margin-bottom:6px;}

/* ---------- Related tools (same-category, scalable to hundreds of tools) ---------- */
.related-tools .related-label{
  font-size:var(--font-size-small);font-weight:600;color:var(--text-muted);
  letter-spacing:0.04em;margin:0 0 14px;
}
.related-tools .row-list{gap:8px;}
.related-tools a.related-link{
  display:flex;justify-content:space-between;gap:8px;
  border:var(--border-default);border-radius:var(--radius);
  padding:10px 12px;font-size:var(--font-size-small);color:var(--text-color);
  text-decoration:none;background:var(--panel-bg);transition:var(--transition-hover);
}
.related-tools a.related-link:hover, .related-tools a.related-link:focus-visible{box-shadow:var(--shadow-pop-sm);transform:var(--hover-lift);}
.related-tools a.related-link span.arrow{color:var(--accent-vivid);}

/* ---------- FAQ (native <details>/<summary>, no JS needed) ---------- */
.faq-item{border-top:1px solid rgba(var(--border-color-rgb),0.2);padding:14px 0;}
.faq-item:first-of-type{border-top:none;padding-top:0;}
.faq-item summary{
  cursor:pointer;list-style:none;
  font-family:var(--font-mono);font-weight:600;
  font-size:var(--font-size-base);color:var(--text-color);
  display:flex;align-items:baseline;gap:10px;
}
.faq-item summary::-webkit-details-marker{display:none;}
.faq-item summary::before{content:'+';color:var(--accent-strong);font-weight:600;flex-shrink:0;}
.faq-item[open] summary::before{content:'\2212';}
.faq-item p{margin:10px 0 0;font-size:var(--font-size-small);color:var(--text-muted);}

/* ---------- Divider + footer ---------- */
/* main's own padding-bottom is 0 (see the base `main{}` rule):
   whatever follows </main> supplies the full top gap itself. 36px on both
   sides matches the site's one standard rhythm instead of the two
   different, smaller ad-hoc values this used before. */
.zigzag-rule{
  height:10px;width:220px;margin:36px auto;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='20' height='10' viewBox='0 0 20 10'%3E%3Cpath d='M0 0 L10 10 L20 0 Z' fill='%23111513'/%3E%3C/svg%3E");
  background-repeat:repeat-x;
}
footer.site-footer{
  max-width:var(--content-width);margin:0 auto;padding:0 24px 40px;
  text-align:center;
}
.copyright{font-size:var(--font-size-base);font-weight:600;color:var(--text-color);margin:0 0 8px;}
.footer-links{display:flex;gap:18px;justify-content:center;font-size:var(--font-size-small);}
/* padding, not just the text's own line height, so the real tap target clears
   WCAG 2.5.8's 24px minimum: the text alone only measured ~21px tall. */
.footer-links a{display:inline-block;color:var(--text-muted);padding:4px 2px;margin:-4px -2px;}

/* ---------- Guides (comparison/how-to content pages) ---------- */
/* A simple two-column comparison table for guide pages: the site had no
   table styling anywhere before this, since every existing tool page's
   content is prose/FAQ, not tabular. Kept generic rather than guide-specific
   so any future content page can reuse it. */
/* display:block + overflow-x:auto so a table wider than the viewport scrolls
   within its own box instead of overflowing the whole page: a real gap on
   every guide page's table at mobile widths, only found by actually measuring
   rendered width rather than assuming width:100% was enough to keep it contained. */
.compare-table{display:block;overflow-x:auto;width:100%;border-collapse:collapse;font-size:var(--font-size-small);margin:0 0 10px;}
.compare-table th, .compare-table td{
  border:var(--border-default);padding:10px 12px;text-align:left;vertical-align:top;
}
.compare-table th{background:var(--accent-soft);color:var(--text-color);font-weight:600;}
.compare-table td{color:var(--text-muted);}
.compare-table tr:first-child th:first-child{border-top-left-radius:var(--radius);}
.compare-table tr:first-child th:last-child{border-top-right-radius:var(--radius);}
