/*! PolyFishCSS.css | v1.0.0-rc.2-rc.1-rc.1-rc.1-rc.1-rc.1 | polyfish.org | MIT
 *  All ten layout, component and utility modules concatenated in load order:
 *  Core -> Grid -> Headers -> Content -> Forms -> Components -> Footers ->
 *  Space -> Utilities.
 *  Fonts is deliberately excluded: it points at /fonts and belongs in its own
 *  request so a project using system faces never downloads it.
 */

/* ===== PolyFishCSS-Core.css ===== */
/*! PolyFishCSS-Core.css | v1.0.0-rc.2-rc.1-rc.1-rc.1-rc.1-rc.1 | polyfish.org | MIT
 *
 * Required base layer: design tokens, reset, typography, layout primitives,
 * buttons and focus handling. Every other module reads the custom properties
 * declared here, so this file always ships.
 *
 * Depends on: nothing.
 * Load order: Core -> Headers -> Content -> Footers -> Utilities.
 *             Utilities must come last; several of its helpers rely on being
 *             the later rule when specificity ties with a component.
 *
 * CONTENTS
 *   1. Tokens
 *   2. Reset
 *   3. Typography
 *   4. Layout primitives
 *   5. Buttons
 *   6. Pills, markers, focus
 *
 * CONVENTIONS
 *   .pf-block            component root
 *   .pf-block__element   part of a component, never used alone
 *   .pf-block--modifier  variant, always applied alongside the root class
 *
 *   Components read role tokens (--pf-accent, --pf-surface, --pf-border) and
 *   never raw palette values, which is what makes a theme a handful of
 *   redeclared properties rather than a fork. See docs/tokens for the list.
 *
 * BROWSER BASELINE
 *   Custom properties, grid, gap, clamp(), clip-path, :focus-visible.
 *   Roughly Chrome 105 / Safari 15.4 / Firefox 103 and newer. Later features
 *   (color-mix, animation-timeline) are used only behind @supports or with a
 *   declared fallback, so nothing breaks on older engines - it just does less.
 *
 * EDITING THIS FILE
 *   Change values in section 1 and leave sections 2-6 alone. If you find
 *   yourself editing a component rule to change a colour, size or radius, the
 *   token you want almost certainly exists.
 */

@layer polyfish.core, polyfish.grid, polyfish.headers, polyfish.content, polyfish.forms, polyfish.components, polyfish.footers, polyfish.space, polyfish.effects, polyfish.utilities, polyfish.fonts, polyfish.compat;

/* ==========================================================================
   CASCADE LAYER
   ==========================================================================
   Everything below sits in `polyfish.core`. The layer order is declared in
   every module, so it holds no matter which order you link the files in.

   Why this matters to you: unlayered CSS beats layered CSS regardless of
   specificity. Your own stylesheet overrides any framework rule with a plain
   class selector — no `!important`, no specificity arms race, no worrying
   about whether Utilities loaded last.

     <link rel="stylesheet" href="PolyFishCSS-Core.min.css">
     <link rel="stylesheet" href="my-app.css">   <!-- wins, always -->

   If you want your CSS layered too, name a layer after the framework's:

     @layer polyfish, app;
     @layer app { .card { background: rebeccapurple; } }
   ========================================================================== */

@layer polyfish.core {
  /* Fonts are loaded with a <link> in <head> — faster than an @import, which
   * blocks this stylesheet. Uncomment the line below if you want Core to be
   * self-contained and are not adding the link tag yourself. */
  /* @import url("https://fonts.googleapis.com/css2?family=Bricolage+Grotesque:opsz,wght@12..96,400..800&family=IBM+Plex+Mono:wght@400;500&family=IBM+Plex+Sans:wght@400;500;600&display=swap"); */
  
  /* ==========================================================================
     #TOKENS
     ========================================================================== */
  
  /**
   * Two layers, on purpose.
   *
   * The palette below is raw material: named colours with no opinion about
   * where they are used. The roles that follow map those colours onto jobs -
   * background, surface, text, accent, border. Components only ever reference
   * roles.
   *
   * That indirection is the whole theming story: redeclare eleven roles in a
   * stylesheet loaded after this one and every module follows, at runtime, with
   * no build step. Redeclaring the palette instead gives you a global shift;
   * redeclaring roles on a wrapper element gives you a scoped one.
   */
  
  :root {
    /* ---------------------------------------------------------------------
       PALETTE — raw colour with no opinion about where it is used.
       Named by position on a scale, never by hue: a token called --pf-blue-800
       holding #f4f7fa in a light theme is a name that lies, and every theme but
       the default made it lie. The neutral ramp runs 50 (lightest) to 950
       (darkest); the two accent hues are numbered, not coloured.
       --------------------------------------------------------------------- */
    --pf-base-900: #00030f;
    --pf-base-800: #000823;
    --pf-base-700: #000f3f;
    --pf-base-600: #17306e;
  
    /* Brand. The mark is a violet body with teal fins, and those two colours
       are deliberately NOT the interface accent: the logo should stay itself
       when a project retints the framework. Named here so brand moments can
       reach for them on purpose instead of hardcoding the hex. */
    --pf-brand: #7c3aed;
    --pf-brand-2: #2dd4bf;
    --pf-brand-deep: #2e1065;
  
    /* Accent hues. --pf-hue-1 is the primary voice, --pf-hue-2 the second.
       A theme redefines these; nothing in the framework assumes they are green
       and apricot, which is exactly why they are not called that. */
    --pf-hue-1: #8fe06a;
    --pf-hue-1-deep: #6dc44a;
    --pf-hue-1-wash: rgba(143, 224, 106, 0.12);
  
    --pf-hue-2: #e5b189;
    --pf-hue-2-deep: #c48f66;
    --pf-hue-2-wash: rgba(229, 177, 137, 0.12);
  
    --pf-base-50: #e9eefa;
    --pf-base-300: #a9bcd8;
    --pf-base-950: #00081f;
  
    /* Roles — override these, not the palette, when reskinning. */
    --pf-bg: var(--pf-base-800);
    --pf-bg-deep: var(--pf-base-900);
    --pf-surface: rgba(255, 255, 255, 0.045);
    --pf-surface-raised: rgba(255, 255, 255, 0.08);
    --pf-text: var(--pf-base-50);
    --pf-text-muted: var(--pf-base-300);
    --pf-accent: var(--pf-hue-1);
    --pf-accent-2: var(--pf-hue-2);
    --pf-border: rgba(169, 188, 216, 0.22);
    --pf-border-strong: rgba(143, 224, 106, 0.42);
    --pf-focus: var(--pf-hue-1);
  
    /* Type */
    --pf-font-display: "Bricolage Grotesque", "Bricolage Fallback", "Trebuchet MS", system-ui, sans-serif;
    --pf-font-body: "Inter", "Inter Fallback", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
    --pf-font-mono: "IBM Plex Mono", "Plex Mono Fallback", ui-monospace, SFMono-Regular, Menlo, monospace;
  
    /* Every step moved up. The smallest size in the framework is 13.6px rather
       than 12px, because 12px legal text is a decision to have it not read. */
    --pf-text-xs: 0.8125rem;
    --pf-text-sm: 0.9375rem;
    --pf-text-base: 1rem;
    --pf-text-lg: 1.1875rem;
    --pf-text-xl: 1.5rem;
    --pf-text-2xl: 1.9375rem;
    --pf-text-3xl: clamp(2.25rem, 1.65rem + 1.9vw, 3rem);
    --pf-text-4xl: clamp(2.75rem, 1.85rem + 3.4vw, 4.4rem);
    --pf-text-5xl: clamp(3.25rem, 1.75rem + 6.2vw, 6rem);
  
    /* Line height is the single largest readability lever after size. 1.7 on
       body copy, tightening as type grows, because a 60px headline at 1.7
       leaves its lines unrelated to each other. */
    --pf-leading-tight: 1.06;
    --pf-leading-snug: 1.22;
    --pf-leading: 1.7;
    --pf-leading-prose: 1.75;
  
    /* 66 characters. The research range for comfortable reading is roughly
       45-75; 66 sits where a long line still returns cleanly to the next. */
    --pf-measure: 66ch;
  
    /* Space — 4px base, doubling at the top end */
    --pf-space-1: 0.25rem;
    --pf-space-2: 0.5rem;
    --pf-space-3: 0.75rem;
    --pf-space-4: 1rem;
    --pf-space-5: 1.5rem;
    --pf-space-6: 2rem;
    --pf-space-7: 3.5rem;
    --pf-space-8: 5.5rem;
    --pf-space-9: 8.5rem;
  
    /* Gaps between grid cells and between a section head and its content. Both
       are their own tokens so density can be tuned without touching the space
       scale that padding depends on. */
    --pf-gap: clamp(1.5rem, 3vw, 2.5rem);
    --pf-gap-lg: clamp(2.5rem, 5.5vw, 4.5rem);
  
    /* Shape — one small radius, one large, one pill. Angles do the rest. */
    --pf-radius-sm: 6px;
    --pf-radius: 12px;
    --pf-radius-lg: 22px;
    --pf-radius-pill: 999px;
    --pf-cut: 18px; /* clipped corner depth for .pf-facet surfaces */
  
    --pf-ring: 0 0 0 3px rgba(143, 224, 106, 0.35);
    /* One shadow was too few once cards, menus and dialogs all needed depth.
       Three steps, all tuned for a dark page: shadows there read as an absence
       of light rather than a grey smear. */
    --pf-shadow-sm: 0 1px 2px rgba(0, 4, 18, 0.4);
    --pf-shadow: 0 8px 20px -12px rgba(0, 4, 18, 0.75);
    --pf-lift: 0 18px 40px -28px rgba(0, 6, 40, 0.9);
  
    /* Vertical rhythm between sections. Raise it for a more spacious site;
       .pf-section--roomy and --vast do exactly that, locally. */
    --pf-section-pad: clamp(5rem, 11vw, 9.5rem);
    --pf-container: 1160px;
    /* Gutters grow with the viewport and never drop below a thumb's width. */
    --pf-gutter: clamp(1.25rem, 5vw, 3rem);
    --pf-speed: 160ms;
    --pf-ease: cubic-bezier(0.2, 0.7, 0.3, 1);
  
    /* The scale mesh. Used by hero, CTA bands and facet surfaces. */
    --pf-mesh: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='72' height='62' viewBox='0 0 72 62'%3E%3Cpath d='M36 1 71 61H1Z' fill='none' stroke='%238fe06a' stroke-opacity='.16' stroke-width='1.4'/%3E%3C/svg%3E");
  
    color-scheme: dark;
  }
  
  /**
   * Automatic light mode
   *
   * The framework ships dark. A site opts into following the operating system
   * by leaving <html> unmarked, and opts out by declaring the theme:
   *
   *   <html lang="en">                     follows the OS
   *   <html lang="en" data-pf-theme="dark">  always dark
   *   <html lang="en" data-pf-theme="light"> always light
   *
   * Only the palette is redeclared. Every role, and therefore every component,
   * follows without a single component rule being touched - which is the whole
   * argument for the two-layer token structure in the first place.
   *
   * The accent darkens in light mode rather than staying put: a pastel green
   * that reads at 6.7:1 on deep blue reads at 1.6:1 on near-white. A palette
   * that does not change with the background is not a palette, it is a
   * decoration.
   *
   * polyfish.org itself sets data-pf-theme="dark", because its identity is the
   * dark page. The capability is here for your projects.
   */
  @media (prefers-color-scheme: light) {
    :root:not([data-pf-theme="dark"]) {
    color-scheme: light;
    --pf-base-900: #e7edf3;
    --pf-base-800: #f4f7fa;
    --pf-base-700: #d6e0e9;
    --pf-base-600: #b9c8d6;
    --pf-hue-1: #45702f;
    --pf-hue-1-deep: #35591f;
    --pf-hue-1-wash: rgba(69, 112, 47, 0.10);
    --pf-hue-2: #9a5620;
    --pf-hue-2-deep: #7d4415;
    --pf-hue-2-wash: rgba(154, 86, 32, 0.10);
    --pf-base-50: #0d2436;
    --pf-base-300: #3f5568;
    --pf-base-950: #f7fbff;
    --pf-surface: rgba(13, 36, 54, 0.045);
    --pf-surface-raised: rgba(13, 36, 54, 0.085);
    --pf-border: rgba(13, 36, 54, 0.16);
    --pf-border-strong: rgba(69, 112, 47, 0.45);
    --pf-mesh: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='72' height='62' viewBox='0 0 72 62'%3E%3Cpath d='M36 1 71 61H1Z' fill='none' stroke='%2345702f' stroke-opacity='.18' stroke-width='1.4'/%3E%3C/svg%3E");
    }
  }
  
  [data-pf-theme="light"] {
    color-scheme: light;
    --pf-base-900: #e7edf3;
    --pf-base-800: #f4f7fa;
    --pf-base-700: #d6e0e9;
    --pf-base-600: #b9c8d6;
    --pf-hue-1: #45702f;
    --pf-hue-1-deep: #35591f;
    --pf-hue-1-wash: rgba(69, 112, 47, 0.10);
    --pf-hue-2: #9a5620;
    --pf-hue-2-deep: #7d4415;
    --pf-hue-2-wash: rgba(154, 86, 32, 0.10);
    --pf-base-50: #0d2436;
    --pf-base-300: #3f5568;
    --pf-base-950: #f7fbff;
    --pf-surface: rgba(13, 36, 54, 0.045);
    --pf-surface-raised: rgba(13, 36, 54, 0.085);
    --pf-border: rgba(13, 36, 54, 0.16);
    --pf-border-strong: rgba(69, 112, 47, 0.45);
    --pf-mesh: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='72' height='62' viewBox='0 0 72 62'%3E%3Cpath d='M36 1 71 61H1Z' fill='none' stroke='%2345702f' stroke-opacity='.18' stroke-width='1.4'/%3E%3C/svg%3E");
  }
  
  /**
   * Light island
   *
   * <section class="pf-invert"> ... </section>
   *
   * Flips the roles to a light palette for one subtree. Put it on <body> for a
   * light site. The doubled class below raises specificity to (0,2,0) so the
   * flip beats a component's own background - .pf-card is (0,1,0) and is
   * declared later in the cascade, so a single class would lose.
   */
  .pf-invert {
    --pf-bg: var(--pf-base-50);
    --pf-bg-deep: #e4eaf9;
    --pf-surface: rgba(0, 15, 63, 0.05);
    --pf-surface-raised: rgba(0, 15, 63, 0.09);
    --pf-text: var(--pf-base-950);
    --pf-text-muted: #3d4e86;
    --pf-border: rgba(0, 15, 63, 0.18);
    --pf-border-strong: rgba(0, 15, 63, 0.4);
  }
  /* Doubled class so the flip beats a component's own background/colour. */
  .pf-invert.pf-invert {
    background-color: var(--pf-bg);
    color: var(--pf-text);
  }
  
  /* ==========================================================================
     #RESET
     ========================================================================== */
  
  /**
   * Deliberately small. Margins are zeroed and reinstated by the components
   * that need them, media elements are made block-level so they stop sitting on
   * the text baseline, and form controls inherit the page font rather than the
   * operating system's. Nothing else is normalised - modern engines agree about
   * far more than they used to.
   */
  
  *,
  *::before,
  *::after { box-sizing: border-box; }
  
  * { margin: 0; }
  
  html {
    -webkit-text-size-adjust: 100%;
    scroll-behavior: smooth;
    scroll-padding-top: 6rem;
  }
  
  body {
    background: var(--pf-bg);
    color: var(--pf-text);
    font-family: var(--pf-font-body);
    /* 17px at phone width, 19px on a desktop. The old 16px baseline is a
       default inherited from 1996 monitors, not a reading decision. */
    font-size: clamp(1.0625rem, 1.01rem + 0.28vw, 1.1875rem);
    line-height: var(--pf-leading);
    /* dvh after vh: on a phone, 100vh is the viewport with the address bar
       hidden, which is taller than what you can actually see. Older engines
       take the first, newer ones the second. */
    min-height: 100vh;
    min-height: 100dvh;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    text-rendering: optimizeLegibility;
    overflow-wrap: break-word;
    /* Inter's optical sizing and tabular figures in tables are handled per
       component; here we only turn on the kerning and ligatures that help at
       reading sizes. */
    font-kerning: normal;
    font-variant-ligatures: common-ligatures;
  }
  
  img,
  svg,
  video,
  canvas { display: block; max-width: 100%; height: auto; }
  
  /* Long URLs and unbroken identifiers are the usual cause of a page scrolling
     sideways on a phone; code is exempt because breaking it changes meaning. */
  pre, code, kbd, samp { overflow-wrap: normal; }
  
  input,
  button,
  textarea,
  select { font: inherit; color: inherit; }
  
  button { background: none; border: 0; }
  
  ul[class],
  ol[class] { list-style: none; padding: 0; }
  
  table { border-collapse: collapse; width: 100%; }
  
  :target { scroll-margin-top: 6rem; }
  
  /* ==========================================================================
     #TYPOGRAPHY
     ========================================================================== */
  
  /**
   * The scale is a minor third at the small end and widens toward the display
   * sizes, where clamp() takes over so headlines shrink on a phone without a
   * media query.
   *
   * p and li carry a max-width of --pf-measure (68ch). This is the one place
   * the framework imposes something on your content, and it is the difference
   * between a readable column and a line the eye cannot track back to. Opt out
   * per element with .pf-measure-none.
   */
  
  h1, h2, h3, h4, h5, h6 {
    font-family: var(--pf-font-display);
    font-weight: 700;
    line-height: var(--pf-leading-snug);
    letter-spacing: -0.015em;
    text-wrap: balance;
  }
  
  h1 { font-size: var(--pf-text-4xl); line-height: var(--pf-leading-tight); letter-spacing: -0.032em; }
  h2 { font-size: var(--pf-text-3xl); letter-spacing: -0.022em; }
  h3 { font-size: var(--pf-text-2xl); letter-spacing: -0.015em; }
  h4 { font-size: var(--pf-text-xl); letter-spacing: -0.01em; }
  h5 { font-size: var(--pf-text-lg); letter-spacing: -0.005em; }
  h6 { font-size: var(--pf-text-base); letter-spacing: 0; }
  
  /* A heading belongs to what follows it, so the space above is larger than the
     space below. Without this a heading floats between two blocks and the page
     reads as a list of fragments. */
  :where(h2, h3, h4) { margin-block-start: 0.4em; }
  
  p, li { max-width: var(--pf-measure); }
  p + p { margin-top: var(--pf-space-5); }
  
  a {
    color: var(--pf-accent);
    /* Underlines are on by default and skip descenders. A link identified only
       by colour fails for anyone who cannot separate that colour from the text
       around it. */
    text-decoration-color: rgba(143, 224, 106, 0.55);
    text-decoration-skip-ink: auto;
    text-underline-offset: 0.18em;
    text-decoration-thickness: 1.5px;
    transition: color var(--pf-speed) var(--pf-ease),
      text-decoration-color var(--pf-speed) var(--pf-ease);
  }
  a:hover { color: var(--pf-base-50); text-decoration-color: currentColor; }
  
  strong, b { font-weight: 600; color: var(--pf-base-50); }
  small { font-size: var(--pf-text-sm); }
  
  code, kbd, samp, pre { font-family: var(--pf-font-mono); font-size: 0.9em; }
  
  :not(pre) > code {
    background: var(--pf-hue-1-wash);
    border: 1px solid rgba(143, 224, 106, 0.22);
    border-radius: var(--pf-radius-sm);
    color: var(--pf-hue-1);
    padding: 0.12em 0.4em;
    white-space: nowrap;
  }
  
  kbd {
    background: var(--pf-surface-raised);
    border: 1px solid var(--pf-border);
    border-bottom-width: 2px;
    border-radius: var(--pf-radius-sm);
    font-size: var(--pf-text-xs);
    padding: 0.15em 0.45em;
  }
  
  hr {
    border: 0;
    border-top: 1px solid var(--pf-border);
    margin-block: var(--pf-space-6);
  }
  
  ::selection { background: var(--pf-hue-1); color: var(--pf-base-950); }
  
  /* Reader-facing lists (not class-styled component lists) */
  .pf-prose { line-height: var(--pf-leading-prose); }
  .pf-prose ul,
  .pf-prose ol { padding-inline-start: 1.4rem; display: grid; gap: var(--pf-space-3); }
  .pf-prose li::marker { color: var(--pf-accent); }
  .pf-prose > * + * { margin-top: var(--pf-space-5); }
  .pf-prose h2 { margin-top: var(--pf-space-8); }
  .pf-prose h3 { margin-top: var(--pf-space-7); }
  .pf-prose h4 { margin-top: var(--pf-space-6); }
  /* A heading immediately after another heading is a subtitle, not a new
     section, so it keeps the tighter spacing. */
  .pf-prose :where(h2, h3, h4) + :where(h2, h3, h4) { margin-top: var(--pf-space-4); }
  .pf-prose h2 + p,
  .pf-prose h3 + p { margin-top: var(--pf-space-4); }
  
  /* ==========================================================================
     #LAYOUT PRIMITIVES
     ========================================================================== */
  
  /**
   * Five primitives cover almost every page: a centred container, a vertical
   * stack, a horizontal cluster that wraps, a column grid, and a two-up split.
   * Compose them instead of writing one-off layout rules.
   *
   *   <div class="pf-container">
   *     <div class="pf-grid pf-grid--3"> ... </div>
   *   </div>
   */
  
  .pf-container {
    width: 100%;
    max-width: var(--pf-container);
    margin-inline: auto;
    /* max() with the safe-area inset keeps content clear of a notch or a
       rounded corner when a phone is held in landscape. It falls back to the
       gutter on every browser that does not know env(). */
    padding-inline: max(var(--pf-gutter), env(safe-area-inset-left), env(safe-area-inset-right));
  }
  .pf-container--narrow { max-width: 780px; }
  .pf-container--wide { max-width: 1360px; }
  
  .pf-stack { display: grid; gap: var(--pf-gap); }
  .pf-stack--sm { gap: var(--pf-space-2); }
  .pf-stack--lg { gap: var(--pf-space-6); }
  
  /* Reading measures. --prose is the long-form column; --wide suits reference
     pages where tables want more room than body copy does. */
  .pf-measure-prose { max-width: 72ch; }
  .pf-measure-wide { max-width: 74ch; }
  
  .pf-cluster {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--pf-space-3);
  }
  .pf-cluster--between { justify-content: space-between; }
  .pf-cluster--center { justify-content: center; }
  
  .pf-grid {
    display: grid;
    gap: var(--pf-gap);
    grid-template-columns: repeat(var(--pf-cols, 1), minmax(0, 1fr));
  }
  .pf-grid--2 { --pf-cols: 2; }
  .pf-grid--3 { --pf-cols: 3; }
  .pf-grid--4 { --pf-cols: 4; }
  /**
   * Auto-fitting grid
   *
   * <div class="pf-grid pf-grid--auto" style="--pf-min: 320px;"> ... </div>
   *
   * Columns are added as they fit rather than at fixed breakpoints. The
   * min(--pf-min, 100%) guard is what stops the track overflowing a viewport
   * narrower than --pf-min itself - without it, a 320px minimum breaks a 300px
   * phone.
   */
  .pf-grid--auto {
    grid-template-columns: repeat(auto-fit, minmax(min(var(--pf-min, 260px), 100%), 1fr));
  }
  /* Named minimums. Set --pf-min directly for anything in between. */
  .pf-grid--auto-sm { --pf-min: 200px; }
  .pf-grid--auto-md { --pf-min: 240px; }
  .pf-grid--auto-lg { --pf-min: 300px; }
  .pf-grid--auto-xl { --pf-min: 340px; }
  
  /**
   * Documentation shell
   *
   * <div class="pf-shell">
   *   <aside class="pf-sidenav"> ... </aside>
   *   <article> ... </article>
   * </div>
   *
   * Sidebar plus body. Collapses to one column below 900px, where a 220px rail
   * would leave the prose too narrow to read. --pf-rail overrides the width.
   */
  .pf-shell {
    display: grid;
    gap: var(--pf-gap-lg);
    grid-template-columns: var(--pf-rail, 220px) minmax(0, 1fr);
  }
  .pf-shell--narrow { --pf-rail: 180px; }
  
  /* Main column plus a secondary panel, for application views. */
  .pf-shell--aside {
    grid-template-columns: minmax(0, 2.2fr) minmax(280px, 1fr);
  }
  
  @media (max-width: 900px) {
    .pf-shell,
    .pf-shell--aside { grid-template-columns: minmax(0, 1fr); }
  }
  
  .pf-split {
    display: grid;
    gap: var(--pf-gap-lg);
    grid-template-columns: repeat(auto-fit, minmax(min(420px, 100%), 1fr));
    align-items: center;
  }
  
  /* A grid child with content wider than its track (a table, a long word, a
     <pre>) will otherwise push the track past 1fr and overflow the page. This
     one line prevents the single most common responsive bug in CSS grid. */
  .pf-grid > *,
  .pf-split > *,
  .pf-shell > * { min-width: 0; }
  
  @media (max-width: 1100px) {
    .pf-grid--4 { --pf-cols: 3; }
  }
  @media (max-width: 900px) {
    .pf-grid--3, .pf-grid--4 { --pf-cols: 2; }
  }
  @media (max-width: 620px) {
    .pf-grid--2, .pf-grid--3, .pf-grid--4 { --pf-cols: 1; }
  }
  
  /**
   * Facet
   *
   * <article class="pf-card pf-facet"> ... </article>
   *
   * One clipped corner, sized by --pf-cut. This is the framework's signature
   * shape; used on every card it becomes wallpaper, so reserve it for the
   * element you want read first. Set --pf-cut: 0 to remove the effect globally
   * without touching a component rule.
   *
   * Note that clip-path cuts everything, including outlines and box-shadows.
   * A focus ring on a clipped element is clipped too, which is why interactive
   * facet cards keep their ring on an inner element.
   */
  /* Brand mark inside a nav or footer lockup. Sized in rem so it tracks the
     surrounding text rather than a fixed pixel box. */
  .pf-logo {
    width: 2.1rem;
    height: 2.1rem;
    flex: none;
  }
  .pf-logo--sm { width: 1.6rem; height: 1.6rem; }
  
  /**
   * Standalone lockup
   *
   * <a class="pf-lockup" href="/"><svg class="pf-logo"></svg> PolyFish</a>
   *
   * The brand mark and wordmark outside a nav or footer - sign-in screens,
   * receipts, standalone panels.
   */
  .pf-lockup {
    display: inline-flex;
    align-items: center;
    gap: 0.6rem;
    color: var(--pf-text);
    font-family: var(--pf-font-display);
    font-size: 1.15rem;
    font-weight: 800;
    letter-spacing: -0.02em;
    text-decoration: none;
  }
  .pf-lockup:hover { color: var(--pf-text); }
  
  /* Brand tints, for the places the mark's own colours belong: a logo well, a
     brand pill, the footer lockup. Everything else uses the accent roles. */
  .pf-brand-well {
    background: color-mix(in srgb, var(--pf-brand) 16%, transparent);
    border: 1px solid color-mix(in srgb, var(--pf-brand) 40%, transparent);
  }
  .pf-fg-brand { color: var(--pf-brand-2); }
  .pf-brand-rule { border-inline-start: 2px solid var(--pf-brand); padding-inline-start: var(--pf-space-4); }
  
  /* Column span helpers for grid children. */
  .pf-span-full { grid-column: 1 / -1; }
  
  /**
   * Stretched link
   *
   * <article class="pf-card pf-relative">
   *   <h3><a class="pf-stretched-link" href="/post">Title</a></h3>
   *   <p>Body copy stays selectable.</p>
   * </article>
   *
   * Makes a whole card clickable from one anchor without wrapping the card in
   * it. The card needs a positioning context - add .pf-relative. Text inside
   * stays selectable, unlike a card-wide anchor, and there is still only one
   * tab stop.
   */
  .pf-stretched-link::after {
    content: "";
    position: absolute;
    inset: 0;
    z-index: 1;
  }
  
  .pf-facet {
    clip-path: polygon(0 0, calc(100% - var(--pf-cut)) 0, 100% var(--pf-cut), 100% 100%, 0 100%);
  }
  .pf-facet--sw {
    clip-path: polygon(0 0, 100% 0, 100% 100%, var(--pf-cut) 100%, 0 calc(100% - var(--pf-cut)));
  }
  
  /* ==========================================================================
     #BUTTONS
     ========================================================================== */
  
  /**
   * Button
   *
   * <a class="pf-btn" href="/get">Get the files</a>
   * <button class="pf-btn pf-btn--secondary pf-btn--sm" type="button">Cancel</button>
   *
   * Variants:  --secondary (outline)  --ghost (bare)  --orange (secondary accent)
   * Sizes:     --sm  --lg  --block (full width)  --square (no pill radius)
   * States:    [disabled] and [aria-disabled="true"] both dim and block pointers
   *
   * The three local properties (--pf-btn-bg/-fg/-border) exist so a variant is
   * three declarations instead of a re-specification of the base. Padding is in
   * em, so a size variant only changes font-size and the shape follows.
   */
  
  .pf-btn {
    --pf-btn-bg: var(--pf-accent);
    --pf-btn-fg: var(--pf-base-950);
    --pf-btn-border: var(--pf-accent);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--pf-space-2);
    background: var(--pf-btn-bg);
    color: var(--pf-btn-fg);
    border: 1.5px solid var(--pf-btn-border);
    border-radius: var(--pf-radius-pill);
    font-family: var(--pf-font-body);
    font-size: var(--pf-text-sm);
    font-weight: 600;
    line-height: 1;
    padding: 0.82em 1.5em;
    text-decoration: none;
    cursor: pointer;
    transition: transform var(--pf-speed) var(--pf-ease),
      background-color var(--pf-speed) var(--pf-ease),
      border-color var(--pf-speed) var(--pf-ease),
      color var(--pf-speed) var(--pf-ease);
  }
  .pf-btn:hover { background: var(--pf-hue-1-deep); border-color: var(--pf-hue-1-deep); color: var(--pf-base-950); }
  .pf-btn:active { transform: translateY(1px); }
  
  .pf-btn--secondary {
    --pf-btn-bg: transparent;
    --pf-btn-fg: var(--pf-text);
    --pf-btn-border: var(--pf-border-strong);
  }
  .pf-btn--secondary:hover {
    background: var(--pf-hue-1-wash);
    border-color: var(--pf-accent);
    color: var(--pf-base-50);
  }
  
  .pf-btn--ghost {
    --pf-btn-bg: transparent;
    --pf-btn-fg: var(--pf-text-muted);
    --pf-btn-border: transparent;
  }
  .pf-btn--ghost:hover { background: var(--pf-surface); border-color: transparent; color: var(--pf-base-50); }
  
  .pf-btn--accent-2 {
    --pf-btn-bg: var(--pf-accent-2);
    --pf-btn-border: var(--pf-accent-2);
  }
  .pf-btn--accent-2:hover { background: var(--pf-hue-2-deep); border-color: var(--pf-hue-2-deep); }
  
  /**
   * Icon-only button
   *
   * <button class="pf-btn pf-btn--secondary pf-btn--icon" type="button"
   *         aria-label="Close">&times;</button>
   *
   * A square target with no text, which means aria-label is not optional - an
   * icon button without one announces as "button" and nothing else.
   */
  .pf-btn--icon {
    width: 2.75rem;
    height: 2.75rem;
    padding: 0;
    border-radius: 50%;
    font-size: var(--pf-text-lg);
    line-height: 1;
  }
  .pf-btn--icon.pf-btn--square { border-radius: var(--pf-radius); }
  .pf-btn--icon.pf-btn--sm { width: 2.25rem; height: 2.25rem; font-size: var(--pf-text-base); }
  
  /* A button that looks like a link but is still a button, for actions that do
     not navigate. Never use an <a> without an href for this. */
  .pf-btn--link {
    --pf-btn-bg: transparent;
    --pf-btn-fg: var(--pf-accent);
    --pf-btn-border: transparent;
    padding-inline: 0.35em;
    text-decoration: underline;
    text-underline-offset: 0.22em;
  }
  .pf-btn--link:hover { background: none; border-color: transparent; color: var(--pf-text); }
  
  /**
   * Busy state
   *
   * <button class="pf-btn" type="button" aria-busy="true" disabled>Saving</button>
   *
   * Driven by aria-busy so the visual and the announced state come from one
   * attribute. The spinner is a pseudo-element, so no markup changes when the
   * state flips.
   */
  .pf-btn[aria-busy="true"] { pointer-events: none; opacity: 0.75; }
  .pf-btn[aria-busy="true"]::before {
    content: "";
    width: 1em;
    height: 1em;
    border-radius: 50%;
    border: 2px solid currentColor;
    border-top-color: transparent;
    animation: pf-btn-spin 0.7s linear infinite;
  }
  @keyframes pf-btn-spin { to { transform: rotate(1turn); } }
  
  .pf-btn--sm { font-size: var(--pf-text-xs); padding: 0.65em 1.15em; }
  .pf-btn--lg { font-size: var(--pf-text-base); padding: 0.95em 2em; }
  .pf-btn--block { display: flex; width: 100%; }
  .pf-btn--square { border-radius: var(--pf-radius); }
  
  .pf-btn[disabled],
  .pf-btn[aria-disabled="true"] { opacity: 0.45; pointer-events: none; }
  
  /* ==========================================================================
     #PILLS, MARKERS, FOCUS
     ========================================================================== */
  
  /**
   * .pf-mark and .pf-dot are the small shapes used in place of tracked-out
   * capital labels: a clipped triangle and a circle, both sized in em so they
   * scale with whatever text they sit beside.
   *
   * The focus ring uses :focus-visible, so it appears for keyboard users and
   * stays out of the way of mouse clicks. It is declared with :where() to keep
   * specificity at zero, which means a component can override it without an
   * !important arms race.
   *
   * The reduced-motion block at the end is a blunt instrument by design: it
   * neutralises every transition and animation in every module at once, so a
   * new component cannot forget to honour the preference.
   */
  
  .pf-pill {
    display: inline-flex;
    align-items: center;
    gap: var(--pf-space-2);
    background: var(--pf-surface);
    border: 1px solid var(--pf-border);
    border-radius: var(--pf-radius-pill);
    color: var(--pf-text-muted);
    font-size: var(--pf-text-xs);
    font-weight: 500;
    padding: 0.4em 0.9em;
  }
  .pf-pill--accent { background: var(--pf-hue-1-wash); border-color: rgba(143, 224, 106, 0.35); color: var(--pf-hue-1); }
  .pf-pill--accent-2 { background: var(--pf-hue-2-wash); border-color: rgba(229, 177, 137, 0.35); color: var(--pf-hue-2); }
  
  /* Small triangle used instead of a tracked-out caps label. */
  .pf-mark {
    display: inline-block;
    width: 0.6em;
    height: 0.6em;
    background: var(--pf-accent);
    clip-path: polygon(50% 0, 100% 100%, 0 100%);
    flex: none;
  }
  .pf-mark--accent-2 { background: var(--pf-accent-2); }
  
  .pf-dot {
    width: 0.5em;
    height: 0.5em;
    border-radius: 50%;
    background: var(--pf-accent);
    flex: none;
  }
  
  :where(a, button, input, select, textarea, summary, [tabindex]):focus-visible {
    outline: 2px solid var(--pf-focus);
    outline-offset: 2px;
    border-radius: var(--pf-radius-sm);
  }
  
  .pf-skip {
    position: absolute;
    inset-inline-start: var(--pf-space-4);
    top: -4rem;
    z-index: 100;
    background: var(--pf-hue-1);
    color: var(--pf-base-950);
    border-radius: var(--pf-radius);
    padding: 0.7em 1.2em;
    font-weight: 600;
    text-decoration: none;
    transition: top var(--pf-speed) var(--pf-ease);
  }
  .pf-skip:focus { top: var(--pf-space-4); color: var(--pf-base-950); }
  
  /**
   * Scroll lock, set by the optional script while a drawer is open.
   *
   * overflow: hidden on <html> rather than <body>, and no position:fixed: the
   * fixed-body trick loses the scroll position and jumps the page to the top
   * on close, which on a long list is the most annoying possible outcome.
   */
  .pf-scroll-lock {
    overflow: hidden;
    /* Compensate for the scrollbar the lock removes, so the page does not
       shift sideways as the drawer opens on a desktop. */
    scrollbar-gutter: stable;
  }
  
  .pf-visually-hidden {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip: rect(0 0 0 0);
    clip-path: inset(50%);
    white-space: nowrap;
  }
  
  /**
   * Touch targets.
   *
   * A 12px small button is about 28px tall, which is under every published
   * minimum for a finger. Rather than inflate every button on every device,
   * raise the floor only where the pointer is coarse - phones, tablets and
   * touch laptops - so mouse users keep the tighter rhythm.
   */
  /**
   * Touch behaviour.
   *
   * touch-action: manipulation removes the 300ms click delay that older mobile
   * browsers add while they wait to see if a tap is a double-tap to zoom. The
   * tap highlight is toned down rather than removed - removing it entirely
   * leaves a touch with no feedback at all until the next paint.
   */
  :where(a, button, label, summary, [role="button"]) {
    touch-action: manipulation;
    -webkit-tap-highlight-color: rgba(143, 224, 106, 0.18);
  }
  
  @media (pointer: coarse) {
    .pf-btn,
    .pf-nav__links a,
    .pf-footer__links a,
    .pf-sidenav__links a,
    .pf-breadcrumb a,
    .pf-social a,
    .pf-totop {
      min-height: 44px;
    }
    .pf-btn { display: inline-flex; align-items: center; }
    .pf-nav__links a,
    .pf-footer__links a,
    .pf-sidenav__links a { display: flex; align-items: center; }
    .pf-choice input { width: 1.25rem; height: 1.25rem; }
  
    /**
     * iOS Safari zooms the page when a field smaller than 16px receives focus,
     * and it does not zoom back out. Any font-size below 16px on a text input
     * is therefore a layout bug on the most common phone in the world. The
     * floor is applied only on touch pointers, so a desktop keeps the tighter
     * scale it was designed with.
     */
    .pf-input,
    .pf-select,
    .pf-textarea,
    .pf-input--sm,
    .pf-select--sm { font-size: 16px; }
  }
  
  /**
   * Short landscape viewports - a phone turned sideways, a 1024x600 laptop.
   * Vertical rhythm tuned for a tall screen eats the whole viewport here, so
   * the section and hero padding is capped rather than scaled.
   */
  @media (max-height: 640px) and (orientation: landscape) {
    :root {
      --pf-section-pad: clamp(2rem, 6vh, 3.5rem);
      --pf-gap-lg: clamp(1.5rem, 4vw, 2.5rem);
    }
  }
  
  /**
   * prefers-contrast: more. Users who ask the OS for stronger contrast get
   * solid borders instead of the hairlines, and muted text moves up to the
   * full-strength colour.
   */
  @media (prefers-contrast: more) {
    :root {
      --pf-border: rgba(232, 240, 246, 0.55);
      --pf-border-strong: var(--pf-accent);
      --pf-text-muted: #d3e2ec;
    }
    .pf-card, .pf-plan, .pf-alert, .pf-table-wrap, .pf-code { border-width: 2px; }
  }
  
  /**
   * Windows High Contrast / forced-colors.
   *
   * The OS replaces every colour with its own palette, which erases anything
   * expressed as a background rather than a border - buttons flatten into the
   * page and the facet corner disappears. Reinstating a border and honouring
   * the system keywords keeps the interface legible there.
   */
  @media (forced-colors: active) {
    .pf-btn,
    .pf-card,
    .pf-plan,
    .pf-alert,
    .pf-input,
    .pf-select,
    .pf-textarea,
    .pf-code { border: 1px solid ButtonBorder; }
  
    .pf-btn { forced-color-adjust: none; background: ButtonFace; color: ButtonText; }
    .pf-mark, .pf-dot { forced-color-adjust: none; background: CanvasText; }
    :where(a, button, input, select, textarea, summary):focus-visible { outline-color: Highlight; }
  }
  
  @media (prefers-reduced-motion: reduce) {
    html { scroll-behavior: auto; }
    *, *::before, *::after {
      animation-duration: 0.01ms !important;
      animation-iteration-count: 1 !important;
      transition-duration: 0.01ms !important;
    }
  }
}

/* ===== PolyFishCSS-Grid.css ===== */
/*! PolyFishCSS-Grid.css | v1.0.0-rc.2-rc.1-rc.1-rc.1-rc.1-rc.1 | polyfish.org | MIT
 *
 * A twelve-column responsive grid, for the times when the Core primitives
 * (.pf-grid, .pf-split, .pf-shell) are not enough and you want explicit
 * control per breakpoint.
 *
 * Depends on: PolyFishCSS-Core.css (gutter and space tokens).
 * Load order: after Core, before Utilities.
 *
 * CONTENTS
 *   1. Rows and columns
 *   2. Column widths, offsets and order
 *   3. Breakpoint variants
 *   4. Row gutters and alignment
 *
 * WHEN NOT TO USE IT
 *   Most layouts do not need a column system. `.pf-grid--3` is one class and
 *   handles its own breakpoints; `.pf-row` plus `.pf-col-md-4` is two classes
 *   per child and handles them by hand. Reach for this when the design really
 *   does change proportion per breakpoint - an 8/4 split that becomes 7/5
 *   before it stacks - and use the primitives everywhere else.
 *
 * MARKUP
 *   <div class="pf-row">
 *     <div class="pf-col-12 pf-col-md-8">main</div>
 *     <div class="pf-col-12 pf-col-md-4">aside</div>
 *   </div>
 *
 * BREAKPOINTS
 *   sm 576px   md 768px   lg 992px   xl 1200px   xxl 1400px
 *   Mobile first: an unprefixed class applies at every width, a prefixed one
 *   applies from that width up.
 */

@layer polyfish.core, polyfish.grid, polyfish.headers, polyfish.content, polyfish.forms, polyfish.components, polyfish.footers, polyfish.space, polyfish.effects, polyfish.utilities, polyfish.fonts, polyfish.compat;

/* ==========================================================================
   CASCADE LAYER
   ==========================================================================
   Everything below sits in `polyfish.grid`. The layer order is declared in
   every module, so it holds no matter which order you link the files in.

   Why this matters to you: unlayered CSS beats layered CSS regardless of
   specificity. Your own stylesheet overrides any framework rule with a plain
   class selector — no `!important`, no specificity arms race, no worrying
   about whether Utilities loaded last.

     <link rel="stylesheet" href="PolyFishCSS-Core.min.css">
     <link rel="stylesheet" href="my-app.css">   <!-- wins, always -->

   If you want your CSS layered too, name a layer after the framework's:

     @layer polyfish, app;
     @layer app { .card { background: rebeccapurple; } }
   ========================================================================== */

@layer polyfish.grid {
  /* ==========================================================================
     #ROWS AND COLUMNS
     ========================================================================== */
  
  /**
   * The row is a twelve-track grid rather than a float or flexbox row, so
   * columns line up vertically as well as horizontally and a short column does
   * not drag the next one up into the gap beside it.
   */
  .pf-row {
    --pf-row-cols: 12;
    display: grid;
    grid-template-columns: repeat(var(--pf-row-cols), minmax(0, 1fr));
    column-gap: var(--pf-gutter-x, var(--pf-gap));
    row-gap: var(--pf-gutter-y, var(--pf-gap));
  }
  
  /* A column with no width takes an equal share of what is left. */
  .pf-col { grid-column: span 1; }
  .pf-col-auto { grid-column: auto; }
  
  /* Every column child gets the overflow guard, for the same reason Core's
     primitives do: a wide table or a long word must not stretch its track. */
  .pf-row > * { min-width: 0; }
  
  /* ==========================================================================
     #COLUMN WIDTHS, OFFSETS AND ORDER
     ========================================================================== */
  .pf-col-1 { grid-column: span 1; }
  .pf-col-2 { grid-column: span 2; }
  .pf-col-3 { grid-column: span 3; }
  .pf-col-4 { grid-column: span 4; }
  .pf-col-5 { grid-column: span 5; }
  .pf-col-6 { grid-column: span 6; }
  .pf-col-7 { grid-column: span 7; }
  .pf-col-8 { grid-column: span 8; }
  .pf-col-9 { grid-column: span 9; }
  .pf-col-10 { grid-column: span 10; }
  .pf-col-11 { grid-column: span 11; }
  .pf-col-12 { grid-column: span 12; }
  
  .pf-offset-0 { margin-inline-start: 0; }
  .pf-offset-1 { margin-inline-start: calc(100% / 12 * 1 + var(--pf-gutter-x, var(--pf-gap)) * 1 / 12); }
  .pf-offset-2 { margin-inline-start: calc(100% / 12 * 2 + var(--pf-gutter-x, var(--pf-gap)) * 2 / 12); }
  .pf-offset-3 { margin-inline-start: calc(100% / 12 * 3 + var(--pf-gutter-x, var(--pf-gap)) * 3 / 12); }
  .pf-offset-4 { margin-inline-start: calc(100% / 12 * 4 + var(--pf-gutter-x, var(--pf-gap)) * 4 / 12); }
  .pf-offset-5 { margin-inline-start: calc(100% / 12 * 5 + var(--pf-gutter-x, var(--pf-gap)) * 5 / 12); }
  .pf-offset-6 { margin-inline-start: calc(100% / 12 * 6 + var(--pf-gutter-x, var(--pf-gap)) * 6 / 12); }
  .pf-offset-7 { margin-inline-start: calc(100% / 12 * 7 + var(--pf-gutter-x, var(--pf-gap)) * 7 / 12); }
  .pf-offset-8 { margin-inline-start: calc(100% / 12 * 8 + var(--pf-gutter-x, var(--pf-gap)) * 8 / 12); }
  .pf-offset-9 { margin-inline-start: calc(100% / 12 * 9 + var(--pf-gutter-x, var(--pf-gap)) * 9 / 12); }
  .pf-offset-10 { margin-inline-start: calc(100% / 12 * 10 + var(--pf-gutter-x, var(--pf-gap)) * 10 / 12); }
  .pf-offset-11 { margin-inline-start: calc(100% / 12 * 11 + var(--pf-gutter-x, var(--pf-gap)) * 11 / 12); }
  
  .pf-order-first { order: -1; }
  .pf-order-last { order: 13; }
  .pf-order-1 { order: 1; }
  .pf-order-2 { order: 2; }
  .pf-order-3 { order: 3; }
  .pf-order-4 { order: 4; }
  .pf-order-5 { order: 5; }
  .pf-order-6 { order: 6; }
  .pf-order-7 { order: 7; }
  .pf-order-8 { order: 8; }
  .pf-order-9 { order: 9; }
  .pf-order-10 { order: 10; }
  .pf-order-11 { order: 11; }
  .pf-order-12 { order: 12; }
  
  /* ==========================================================================
     #BREAKPOINT VARIANTS
     ========================================================================== */
  
  @media (min-width: 576px) {
    .pf-col-sm-auto { grid-column: auto; }
    .pf-col-sm-1 { grid-column: span 1; }
    .pf-col-sm-2 { grid-column: span 2; }
    .pf-col-sm-3 { grid-column: span 3; }
    .pf-col-sm-4 { grid-column: span 4; }
    .pf-col-sm-5 { grid-column: span 5; }
    .pf-col-sm-6 { grid-column: span 6; }
    .pf-col-sm-7 { grid-column: span 7; }
    .pf-col-sm-8 { grid-column: span 8; }
    .pf-col-sm-9 { grid-column: span 9; }
    .pf-col-sm-10 { grid-column: span 10; }
    .pf-col-sm-11 { grid-column: span 11; }
    .pf-col-sm-12 { grid-column: span 12; }
    .pf-offset-sm-1 { margin-inline-start: calc(100% / 12 * 1 + var(--pf-gutter-x, var(--pf-gap)) * 1 / 12); }
    .pf-offset-sm-2 { margin-inline-start: calc(100% / 12 * 2 + var(--pf-gutter-x, var(--pf-gap)) * 2 / 12); }
    .pf-offset-sm-3 { margin-inline-start: calc(100% / 12 * 3 + var(--pf-gutter-x, var(--pf-gap)) * 3 / 12); }
    .pf-offset-sm-4 { margin-inline-start: calc(100% / 12 * 4 + var(--pf-gutter-x, var(--pf-gap)) * 4 / 12); }
    .pf-offset-sm-5 { margin-inline-start: calc(100% / 12 * 5 + var(--pf-gutter-x, var(--pf-gap)) * 5 / 12); }
    .pf-offset-sm-6 { margin-inline-start: calc(100% / 12 * 6 + var(--pf-gutter-x, var(--pf-gap)) * 6 / 12); }
    .pf-offset-sm-7 { margin-inline-start: calc(100% / 12 * 7 + var(--pf-gutter-x, var(--pf-gap)) * 7 / 12); }
    .pf-offset-sm-8 { margin-inline-start: calc(100% / 12 * 8 + var(--pf-gutter-x, var(--pf-gap)) * 8 / 12); }
    .pf-offset-sm-9 { margin-inline-start: calc(100% / 12 * 9 + var(--pf-gutter-x, var(--pf-gap)) * 9 / 12); }
    .pf-offset-sm-10 { margin-inline-start: calc(100% / 12 * 10 + var(--pf-gutter-x, var(--pf-gap)) * 10 / 12); }
    .pf-offset-sm-11 { margin-inline-start: calc(100% / 12 * 11 + var(--pf-gutter-x, var(--pf-gap)) * 11 / 12); }
    .pf-offset-sm-0 { margin-inline-start: 0; }
    .pf-order-sm-1 { order: 1; }
    .pf-order-sm-2 { order: 2; }
    .pf-order-sm-3 { order: 3; }
    .pf-order-sm-4 { order: 4; }
    .pf-order-sm-5 { order: 5; }
    .pf-order-sm-6 { order: 6; }
    .pf-order-sm-7 { order: 7; }
    .pf-order-sm-8 { order: 8; }
    .pf-order-sm-9 { order: 9; }
    .pf-order-sm-10 { order: 10; }
    .pf-order-sm-11 { order: 11; }
    .pf-order-sm-12 { order: 12; }
  }
  
  @media (min-width: 768px) {
    .pf-col-md-auto { grid-column: auto; }
    .pf-col-md-1 { grid-column: span 1; }
    .pf-col-md-2 { grid-column: span 2; }
    .pf-col-md-3 { grid-column: span 3; }
    .pf-col-md-4 { grid-column: span 4; }
    .pf-col-md-5 { grid-column: span 5; }
    .pf-col-md-6 { grid-column: span 6; }
    .pf-col-md-7 { grid-column: span 7; }
    .pf-col-md-8 { grid-column: span 8; }
    .pf-col-md-9 { grid-column: span 9; }
    .pf-col-md-10 { grid-column: span 10; }
    .pf-col-md-11 { grid-column: span 11; }
    .pf-col-md-12 { grid-column: span 12; }
    .pf-offset-md-1 { margin-inline-start: calc(100% / 12 * 1 + var(--pf-gutter-x, var(--pf-gap)) * 1 / 12); }
    .pf-offset-md-2 { margin-inline-start: calc(100% / 12 * 2 + var(--pf-gutter-x, var(--pf-gap)) * 2 / 12); }
    .pf-offset-md-3 { margin-inline-start: calc(100% / 12 * 3 + var(--pf-gutter-x, var(--pf-gap)) * 3 / 12); }
    .pf-offset-md-4 { margin-inline-start: calc(100% / 12 * 4 + var(--pf-gutter-x, var(--pf-gap)) * 4 / 12); }
    .pf-offset-md-5 { margin-inline-start: calc(100% / 12 * 5 + var(--pf-gutter-x, var(--pf-gap)) * 5 / 12); }
    .pf-offset-md-6 { margin-inline-start: calc(100% / 12 * 6 + var(--pf-gutter-x, var(--pf-gap)) * 6 / 12); }
    .pf-offset-md-7 { margin-inline-start: calc(100% / 12 * 7 + var(--pf-gutter-x, var(--pf-gap)) * 7 / 12); }
    .pf-offset-md-8 { margin-inline-start: calc(100% / 12 * 8 + var(--pf-gutter-x, var(--pf-gap)) * 8 / 12); }
    .pf-offset-md-9 { margin-inline-start: calc(100% / 12 * 9 + var(--pf-gutter-x, var(--pf-gap)) * 9 / 12); }
    .pf-offset-md-10 { margin-inline-start: calc(100% / 12 * 10 + var(--pf-gutter-x, var(--pf-gap)) * 10 / 12); }
    .pf-offset-md-11 { margin-inline-start: calc(100% / 12 * 11 + var(--pf-gutter-x, var(--pf-gap)) * 11 / 12); }
    .pf-offset-md-0 { margin-inline-start: 0; }
    .pf-order-md-1 { order: 1; }
    .pf-order-md-2 { order: 2; }
    .pf-order-md-3 { order: 3; }
    .pf-order-md-4 { order: 4; }
    .pf-order-md-5 { order: 5; }
    .pf-order-md-6 { order: 6; }
    .pf-order-md-7 { order: 7; }
    .pf-order-md-8 { order: 8; }
    .pf-order-md-9 { order: 9; }
    .pf-order-md-10 { order: 10; }
    .pf-order-md-11 { order: 11; }
    .pf-order-md-12 { order: 12; }
  }
  
  @media (min-width: 992px) {
    .pf-col-lg-auto { grid-column: auto; }
    .pf-col-lg-1 { grid-column: span 1; }
    .pf-col-lg-2 { grid-column: span 2; }
    .pf-col-lg-3 { grid-column: span 3; }
    .pf-col-lg-4 { grid-column: span 4; }
    .pf-col-lg-5 { grid-column: span 5; }
    .pf-col-lg-6 { grid-column: span 6; }
    .pf-col-lg-7 { grid-column: span 7; }
    .pf-col-lg-8 { grid-column: span 8; }
    .pf-col-lg-9 { grid-column: span 9; }
    .pf-col-lg-10 { grid-column: span 10; }
    .pf-col-lg-11 { grid-column: span 11; }
    .pf-col-lg-12 { grid-column: span 12; }
    .pf-offset-lg-1 { margin-inline-start: calc(100% / 12 * 1 + var(--pf-gutter-x, var(--pf-gap)) * 1 / 12); }
    .pf-offset-lg-2 { margin-inline-start: calc(100% / 12 * 2 + var(--pf-gutter-x, var(--pf-gap)) * 2 / 12); }
    .pf-offset-lg-3 { margin-inline-start: calc(100% / 12 * 3 + var(--pf-gutter-x, var(--pf-gap)) * 3 / 12); }
    .pf-offset-lg-4 { margin-inline-start: calc(100% / 12 * 4 + var(--pf-gutter-x, var(--pf-gap)) * 4 / 12); }
    .pf-offset-lg-5 { margin-inline-start: calc(100% / 12 * 5 + var(--pf-gutter-x, var(--pf-gap)) * 5 / 12); }
    .pf-offset-lg-6 { margin-inline-start: calc(100% / 12 * 6 + var(--pf-gutter-x, var(--pf-gap)) * 6 / 12); }
    .pf-offset-lg-7 { margin-inline-start: calc(100% / 12 * 7 + var(--pf-gutter-x, var(--pf-gap)) * 7 / 12); }
    .pf-offset-lg-8 { margin-inline-start: calc(100% / 12 * 8 + var(--pf-gutter-x, var(--pf-gap)) * 8 / 12); }
    .pf-offset-lg-9 { margin-inline-start: calc(100% / 12 * 9 + var(--pf-gutter-x, var(--pf-gap)) * 9 / 12); }
    .pf-offset-lg-10 { margin-inline-start: calc(100% / 12 * 10 + var(--pf-gutter-x, var(--pf-gap)) * 10 / 12); }
    .pf-offset-lg-11 { margin-inline-start: calc(100% / 12 * 11 + var(--pf-gutter-x, var(--pf-gap)) * 11 / 12); }
    .pf-offset-lg-0 { margin-inline-start: 0; }
    .pf-order-lg-1 { order: 1; }
    .pf-order-lg-2 { order: 2; }
    .pf-order-lg-3 { order: 3; }
    .pf-order-lg-4 { order: 4; }
    .pf-order-lg-5 { order: 5; }
    .pf-order-lg-6 { order: 6; }
    .pf-order-lg-7 { order: 7; }
    .pf-order-lg-8 { order: 8; }
    .pf-order-lg-9 { order: 9; }
    .pf-order-lg-10 { order: 10; }
    .pf-order-lg-11 { order: 11; }
    .pf-order-lg-12 { order: 12; }
  }
  
  @media (min-width: 1200px) {
    .pf-col-xl-auto { grid-column: auto; }
    .pf-col-xl-1 { grid-column: span 1; }
    .pf-col-xl-2 { grid-column: span 2; }
    .pf-col-xl-3 { grid-column: span 3; }
    .pf-col-xl-4 { grid-column: span 4; }
    .pf-col-xl-5 { grid-column: span 5; }
    .pf-col-xl-6 { grid-column: span 6; }
    .pf-col-xl-7 { grid-column: span 7; }
    .pf-col-xl-8 { grid-column: span 8; }
    .pf-col-xl-9 { grid-column: span 9; }
    .pf-col-xl-10 { grid-column: span 10; }
    .pf-col-xl-11 { grid-column: span 11; }
    .pf-col-xl-12 { grid-column: span 12; }
    .pf-offset-xl-1 { margin-inline-start: calc(100% / 12 * 1 + var(--pf-gutter-x, var(--pf-gap)) * 1 / 12); }
    .pf-offset-xl-2 { margin-inline-start: calc(100% / 12 * 2 + var(--pf-gutter-x, var(--pf-gap)) * 2 / 12); }
    .pf-offset-xl-3 { margin-inline-start: calc(100% / 12 * 3 + var(--pf-gutter-x, var(--pf-gap)) * 3 / 12); }
    .pf-offset-xl-4 { margin-inline-start: calc(100% / 12 * 4 + var(--pf-gutter-x, var(--pf-gap)) * 4 / 12); }
    .pf-offset-xl-5 { margin-inline-start: calc(100% / 12 * 5 + var(--pf-gutter-x, var(--pf-gap)) * 5 / 12); }
    .pf-offset-xl-6 { margin-inline-start: calc(100% / 12 * 6 + var(--pf-gutter-x, var(--pf-gap)) * 6 / 12); }
    .pf-offset-xl-7 { margin-inline-start: calc(100% / 12 * 7 + var(--pf-gutter-x, var(--pf-gap)) * 7 / 12); }
    .pf-offset-xl-8 { margin-inline-start: calc(100% / 12 * 8 + var(--pf-gutter-x, var(--pf-gap)) * 8 / 12); }
    .pf-offset-xl-9 { margin-inline-start: calc(100% / 12 * 9 + var(--pf-gutter-x, var(--pf-gap)) * 9 / 12); }
    .pf-offset-xl-10 { margin-inline-start: calc(100% / 12 * 10 + var(--pf-gutter-x, var(--pf-gap)) * 10 / 12); }
    .pf-offset-xl-11 { margin-inline-start: calc(100% / 12 * 11 + var(--pf-gutter-x, var(--pf-gap)) * 11 / 12); }
    .pf-offset-xl-0 { margin-inline-start: 0; }
    .pf-order-xl-1 { order: 1; }
    .pf-order-xl-2 { order: 2; }
    .pf-order-xl-3 { order: 3; }
    .pf-order-xl-4 { order: 4; }
    .pf-order-xl-5 { order: 5; }
    .pf-order-xl-6 { order: 6; }
    .pf-order-xl-7 { order: 7; }
    .pf-order-xl-8 { order: 8; }
    .pf-order-xl-9 { order: 9; }
    .pf-order-xl-10 { order: 10; }
    .pf-order-xl-11 { order: 11; }
    .pf-order-xl-12 { order: 12; }
  }
  
  @media (min-width: 1400px) {
    .pf-col-xxl-auto { grid-column: auto; }
    .pf-col-xxl-1 { grid-column: span 1; }
    .pf-col-xxl-2 { grid-column: span 2; }
    .pf-col-xxl-3 { grid-column: span 3; }
    .pf-col-xxl-4 { grid-column: span 4; }
    .pf-col-xxl-5 { grid-column: span 5; }
    .pf-col-xxl-6 { grid-column: span 6; }
    .pf-col-xxl-7 { grid-column: span 7; }
    .pf-col-xxl-8 { grid-column: span 8; }
    .pf-col-xxl-9 { grid-column: span 9; }
    .pf-col-xxl-10 { grid-column: span 10; }
    .pf-col-xxl-11 { grid-column: span 11; }
    .pf-col-xxl-12 { grid-column: span 12; }
    .pf-offset-xxl-1 { margin-inline-start: calc(100% / 12 * 1 + var(--pf-gutter-x, var(--pf-gap)) * 1 / 12); }
    .pf-offset-xxl-2 { margin-inline-start: calc(100% / 12 * 2 + var(--pf-gutter-x, var(--pf-gap)) * 2 / 12); }
    .pf-offset-xxl-3 { margin-inline-start: calc(100% / 12 * 3 + var(--pf-gutter-x, var(--pf-gap)) * 3 / 12); }
    .pf-offset-xxl-4 { margin-inline-start: calc(100% / 12 * 4 + var(--pf-gutter-x, var(--pf-gap)) * 4 / 12); }
    .pf-offset-xxl-5 { margin-inline-start: calc(100% / 12 * 5 + var(--pf-gutter-x, var(--pf-gap)) * 5 / 12); }
    .pf-offset-xxl-6 { margin-inline-start: calc(100% / 12 * 6 + var(--pf-gutter-x, var(--pf-gap)) * 6 / 12); }
    .pf-offset-xxl-7 { margin-inline-start: calc(100% / 12 * 7 + var(--pf-gutter-x, var(--pf-gap)) * 7 / 12); }
    .pf-offset-xxl-8 { margin-inline-start: calc(100% / 12 * 8 + var(--pf-gutter-x, var(--pf-gap)) * 8 / 12); }
    .pf-offset-xxl-9 { margin-inline-start: calc(100% / 12 * 9 + var(--pf-gutter-x, var(--pf-gap)) * 9 / 12); }
    .pf-offset-xxl-10 { margin-inline-start: calc(100% / 12 * 10 + var(--pf-gutter-x, var(--pf-gap)) * 10 / 12); }
    .pf-offset-xxl-11 { margin-inline-start: calc(100% / 12 * 11 + var(--pf-gutter-x, var(--pf-gap)) * 11 / 12); }
    .pf-offset-xxl-0 { margin-inline-start: 0; }
    .pf-order-xxl-1 { order: 1; }
    .pf-order-xxl-2 { order: 2; }
    .pf-order-xxl-3 { order: 3; }
    .pf-order-xxl-4 { order: 4; }
    .pf-order-xxl-5 { order: 5; }
    .pf-order-xxl-6 { order: 6; }
    .pf-order-xxl-7 { order: 7; }
    .pf-order-xxl-8 { order: 8; }
    .pf-order-xxl-9 { order: 9; }
    .pf-order-xxl-10 { order: 10; }
    .pf-order-xxl-11 { order: 11; }
    .pf-order-xxl-12 { order: 12; }
  }
  
  /* ==========================================================================
     #ROW GUTTERS AND ALIGNMENT
     ========================================================================== */
  
  /**
   * Gutters are two custom properties, so a row can be tightened or opened up
   * without a modifier per size:
   *   <div class="pf-row pf-g-0">        no gutters at all
   *   <div class="pf-row pf-gx-5 pf-gy-2"> wide columns, tight rows
   */
  .pf-g-0  { --pf-gutter-x: 0; --pf-gutter-y: 0; }
  .pf-g-1  { --pf-gutter-x: var(--pf-space-1); --pf-gutter-y: var(--pf-space-1); }
  .pf-g-2  { --pf-gutter-x: var(--pf-space-2); --pf-gutter-y: var(--pf-space-2); }
  .pf-g-3  { --pf-gutter-x: var(--pf-space-3); --pf-gutter-y: var(--pf-space-3); }
  .pf-g-4  { --pf-gutter-x: var(--pf-space-4); --pf-gutter-y: var(--pf-space-4); }
  .pf-g-5  { --pf-gutter-x: var(--pf-space-5); --pf-gutter-y: var(--pf-space-5); }
  .pf-g-6  { --pf-gutter-x: var(--pf-space-6); --pf-gutter-y: var(--pf-space-6); }
  
  .pf-gx-0 { --pf-gutter-x: 0; }
  .pf-gx-2 { --pf-gutter-x: var(--pf-space-2); }
  .pf-gx-4 { --pf-gutter-x: var(--pf-space-4); }
  .pf-gx-6 { --pf-gutter-x: var(--pf-space-6); }
  .pf-gy-0 { --pf-gutter-y: 0; }
  .pf-gy-2 { --pf-gutter-y: var(--pf-space-2); }
  .pf-gy-4 { --pf-gutter-y: var(--pf-space-4); }
  .pf-gy-6 { --pf-gutter-y: var(--pf-space-6); }
  
  /* Alignment within the row. align-* is the cross axis, justify-* the main. */
  .pf-row--top { align-items: start; }
  .pf-row--middle { align-items: center; }
  .pf-row--bottom { align-items: end; }
  .pf-row--stretch { align-items: stretch; }
  
  /* Equal-height children regardless of content, for card rows. */
  .pf-row--equal > * { display: flex; }
  .pf-row--equal > * > * { flex: 1; }
  
  /**
   * Auto-columns: n equal tracks with no per-child classes, the shorthand for
   * the common case.
   *   <div class="pf-row pf-row-cols-3"> three equal columns
   */
  .pf-row-cols-1 { --pf-row-cols: 1; }
  .pf-row-cols-2 { --pf-row-cols: 2; }
  .pf-row-cols-3 { --pf-row-cols: 3; }
  .pf-row-cols-4 { --pf-row-cols: 4; }
  .pf-row-cols-6 { --pf-row-cols: 6; }
  .pf-row-cols-1 > *, .pf-row-cols-2 > *, .pf-row-cols-3 > *,
  .pf-row-cols-4 > *, .pf-row-cols-6 > * { grid-column: span 1; }
  
  @media (min-width: 576px) {
    .pf-row-cols-sm-1 { --pf-row-cols: 1; }
    .pf-row-cols-sm-2 { --pf-row-cols: 2; }
    .pf-row-cols-sm-3 { --pf-row-cols: 3; }
    .pf-row-cols-sm-4 { --pf-row-cols: 4; }
    .pf-row-cols-sm-6 { --pf-row-cols: 6; }
  }
  @media (min-width: 768px) {
    .pf-row-cols-md-1 { --pf-row-cols: 1; }
    .pf-row-cols-md-2 { --pf-row-cols: 2; }
    .pf-row-cols-md-3 { --pf-row-cols: 3; }
    .pf-row-cols-md-4 { --pf-row-cols: 4; }
    .pf-row-cols-md-6 { --pf-row-cols: 6; }
  }
  @media (min-width: 992px) {
    .pf-row-cols-lg-1 { --pf-row-cols: 1; }
    .pf-row-cols-lg-2 { --pf-row-cols: 2; }
    .pf-row-cols-lg-3 { --pf-row-cols: 3; }
    .pf-row-cols-lg-4 { --pf-row-cols: 4; }
    .pf-row-cols-lg-6 { --pf-row-cols: 6; }
  }
  @media (min-width: 1200px) {
    .pf-row-cols-xl-1 { --pf-row-cols: 1; }
    .pf-row-cols-xl-2 { --pf-row-cols: 2; }
    .pf-row-cols-xl-3 { --pf-row-cols: 3; }
    .pf-row-cols-xl-4 { --pf-row-cols: 4; }
    .pf-row-cols-xl-6 { --pf-row-cols: 6; }
  }
}

/* ===== PolyFishCSS-Headers.css ===== */
/*! PolyFishCSS-Headers.css | v1.0.0-rc.2-rc.1-rc.1-rc.1-rc.1-rc.1 | polyfish.org | MIT
 *
 * Everything above the fold: announcement bar, sticky navigation, hero
 * variants, interior page headers and breadcrumbs. Needs no script - the
 * mobile menu is a checkbox and a sibling selector.
 *
 * Depends on: PolyFishCSS-Core.css (tokens, buttons, container).
 * Load order: Core -> Headers -> Content -> Footers -> Utilities.
 *             Utilities must come last; several of its helpers rely on being
 *             the later rule when specificity ties with a component.
 *
 * CONTENTS
 *   1. Announcement bar
 *   2. Navigation
 *   3. Hero
 *   4. Interior page header + breadcrumbs
 *
 * CONVENTIONS
 *   .pf-block            component root
 *   .pf-block__element   part of a component, never used alone
 *   .pf-block--modifier  variant, always applied alongside the root class
 *
 *   Components read role tokens (--pf-accent, --pf-surface, --pf-border) and
 *   never raw palette values, which is what makes a theme a handful of
 *   redeclared properties rather than a fork. See docs/tokens for the list.
 *
 * BROWSER BASELINE
 *   Custom properties, grid, gap, clamp(), clip-path, :focus-visible.
 *   Roughly Chrome 105 / Safari 15.4 / Firefox 103 and newer. Later features
 *   (color-mix, animation-timeline) are used only behind @supports or with a
 *   declared fallback, so nothing breaks on older engines - it just does less.
 */

@layer polyfish.core, polyfish.grid, polyfish.headers, polyfish.content, polyfish.forms, polyfish.components, polyfish.footers, polyfish.space, polyfish.effects, polyfish.utilities, polyfish.fonts, polyfish.compat;

/* ==========================================================================
   CASCADE LAYER
   ==========================================================================
   Everything below sits in `polyfish.headers`. The layer order is declared in
   every module, so it holds no matter which order you link the files in.

   Why this matters to you: unlayered CSS beats layered CSS regardless of
   specificity. Your own stylesheet overrides any framework rule with a plain
   class selector — no `!important`, no specificity arms race, no worrying
   about whether Utilities loaded last.

     <link rel="stylesheet" href="PolyFishCSS-Core.min.css">
     <link rel="stylesheet" href="my-app.css">   <!-- wins, always -->

   If you want your CSS layered too, name a layer after the framework's:

     @layer polyfish, app;
     @layer app { .card { background: rebeccapurple; } }
   ========================================================================== */

@layer polyfish.headers {
  /* ==========================================================================
     #ANNOUNCEMENT BAR
     ========================================================================== */
  
  /**
   * Top bar
   *
   * <div class="pf-topbar">
   *   <div class="pf-container pf-topbar__inner"> ... </div>
   * </div>
   *
   * Variant: --green fills with the accent and recolours its own links.
   * Sits above .pf-nav in the markup so the sticky navigation scrolls over it.
   */
  
  .pf-topbar {
    background: var(--pf-base-900);
    border-bottom: 1px solid var(--pf-border);
    color: var(--pf-text-muted);
    font-size: var(--pf-text-xs);
  }
  .pf-topbar__inner {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: center;
    gap: var(--pf-space-3);
    padding-block: 0.65rem;
    text-align: center;
  }
  .pf-topbar a { font-weight: 500; }
  .pf-topbar--accent { background: var(--pf-hue-1); border-color: transparent; color: var(--pf-base-950); }
  .pf-topbar--accent a { color: var(--pf-base-950); text-decoration-color: rgba(0, 16, 58, 0.5); }
  
  /* ==========================================================================
     #NAVIGATION
     ========================================================================== */
  
  /**
   * Navigation
   *
   * <header class="pf-nav">
   *   <div class="pf-container pf-nav__inner">
   *     <a class="pf-nav__brand" href="/">Brand</a>
   *
   *     <input type="checkbox" id="pf-nav-toggle" class="pf-nav__checkbox">
   *     <label class="pf-nav__burger" for="pf-nav-toggle"><span></span></label>
   *
   *     <div class="pf-nav__menu">
   *       <ul class="pf-nav__links"> ... </ul>
   *       <div class="pf-nav__actions"> ... </div>
   *     </div>
   *   </div>
   * </header>
   *
   * Variants: --static (scrolls away)  --flush (transparent, over a photo hero)
   *
   * ORDER MATTERS. The checkbox must precede .pf-nav__menu, because the open
   * state is expressed as :checked ~ .pf-nav__menu and the subsequent-sibling
   * combinator only looks forward. Move the input and the menu stops opening.
   *
   * Mark the current page with aria-current on its link; the underline is
   * styled off that attribute rather than a modifier class, so the
   * accessibility hint and the visual state cannot drift apart.
   */
  
  .pf-nav {
    position: sticky;
    top: 0;
    z-index: 50;
    background: var(--pf-bg); /* fallback where color-mix is unsupported */
    background: color-mix(in srgb, var(--pf-bg) 88%, transparent);
    -webkit-backdrop-filter: blur(14px);
    backdrop-filter: blur(14px);
    border-bottom: 1px solid var(--pf-border);
  }
  .pf-nav--static { position: static; -webkit-backdrop-filter: none; backdrop-filter: none; }
  .pf-nav--flush { background: transparent; border-bottom-color: transparent; }
  
  .pf-nav__inner {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--pf-space-5);
    min-height: 4.5rem;
  }
  
  .pf-nav__brand {
    display: inline-flex;
    align-items: center;
    gap: 0.6rem;
    color: var(--pf-text);
    font-family: var(--pf-font-display);
    font-size: 1.2rem;
    font-weight: 800;
    letter-spacing: -0.02em;
    text-decoration: none;
    flex: none;
  }
  .pf-nav__brand:hover { color: var(--pf-text); }
  .pf-nav__brand img,
  .pf-nav__brand svg { width: 2.1rem; height: 2.1rem; }
  .pf-nav__brand small {
    align-self: center;
    color: var(--pf-text-muted);
    font-family: var(--pf-font-mono);
    font-size: 0.62rem;
    font-weight: 400;
    border: 1px solid var(--pf-border);
    border-radius: var(--pf-radius-pill);
    padding: 0.1rem 0.5rem;
  }
  
  .pf-nav__menu {
    display: flex;
    align-items: center;
    gap: var(--pf-space-6);
    margin-inline-start: auto;
  }
  
  .pf-nav__links {
    display: flex;
    align-items: center;
    gap: var(--pf-space-5);
    margin: 0;
  }
  .pf-nav__links a {
    color: var(--pf-text-muted);
    font-size: var(--pf-text-base);
    font-weight: 500;
    text-decoration: none;
    padding-block: 0.4rem;
    position: relative;
  }
  .pf-nav__links a:hover { color: var(--pf-base-50); }
  .pf-nav__links a[aria-current] { color: var(--pf-base-50); }
  .pf-nav__links a[aria-current]::after {
    content: "";
    position: absolute;
    inset-inline-start: 0;
    inset-inline-end: 0;
    bottom: -0.15rem;
    height: 2px;
    background: var(--pf-accent);
  }
  
  .pf-nav__actions {
    display: flex;
    align-items: center;
    gap: var(--pf-space-3);
  }
  
  /**
   * The checkbox is visually hidden but not display:none - it has to stay
   * focusable so the menu is reachable by keyboard. The label is its accessible
   * hit area and carries a visually-hidden text node for screen readers.
   */
  .pf-nav__checkbox { position: absolute; opacity: 0; pointer-events: none; }
  
  .pf-nav__burger {
    display: none;
    width: 2.75rem;
    height: 2.75rem;
    border: 1px solid var(--pf-border);
    border-radius: var(--pf-radius);
    cursor: pointer;
    place-items: center;
  }
  .pf-nav__burger span,
  .pf-nav__burger span::before,
  .pf-nav__burger span::after {
    display: block;
    width: 1.1rem;
    height: 2px;
    background: var(--pf-text);
    content: "";
    transition: transform var(--pf-speed) var(--pf-ease), opacity var(--pf-speed) var(--pf-ease);
  }
  .pf-nav__burger span::before { transform: translateY(-6px); }
  .pf-nav__burger span::after { transform: translateY(4px); }
  .pf-nav__checkbox:focus-visible + .pf-nav__burger { outline: 2px solid var(--pf-focus); outline-offset: 2px; }
  
  @media (max-width: 860px) {
    .pf-nav__burger { display: grid; }
    .pf-nav__menu {
      position: absolute;
      inset: 100% 0 auto;
      display: grid;
      gap: var(--pf-space-4);
      background: var(--pf-base-900);
      border-bottom: 1px solid var(--pf-border);
      padding: var(--pf-space-5) var(--pf-gutter) var(--pf-space-6);
      /* A long menu on a short phone has to scroll rather than run off the
         bottom of the screen with no way to reach the last item. dvh, not vh,
         because vh on mobile is the viewport with the address bar hidden. */
      max-height: calc(100dvh - 4.5rem);
      overflow-y: auto;
      overscroll-behavior: contain;
      padding-bottom: max(var(--pf-space-6), env(safe-area-inset-bottom));
      visibility: hidden;
      opacity: 0;
      transform: translateY(-0.5rem);
      transition: opacity var(--pf-speed) var(--pf-ease), transform var(--pf-speed) var(--pf-ease),
        visibility var(--pf-speed);
    }
    .pf-nav__checkbox:checked ~ .pf-nav__menu { visibility: visible; opacity: 1; transform: none; }
    .pf-nav__checkbox:checked ~ .pf-nav__burger span { background: transparent; }
    .pf-nav__checkbox:checked ~ .pf-nav__burger span::before { transform: rotate(45deg); }
    .pf-nav__checkbox:checked ~ .pf-nav__burger span::after { transform: rotate(-45deg); }
    .pf-nav__links { flex-direction: column; align-items: stretch; gap: var(--pf-space-1); }
    .pf-nav__links a { font-size: var(--pf-text-lg); padding-block: 0.5rem; }
    .pf-nav__actions { flex-direction: column; align-items: stretch; }
    .pf-nav__inner { position: relative; }
  }
  
  /* ==========================================================================
     #HERO
     ========================================================================== */
  
  /**
   * Hero
   *
   * <section class="pf-hero pf-hero--split">
   *   <div class="pf-container pf-hero__inner">
   *     <div>
   *       <p class="pf-hero__eyebrow"> ... </p>
   *       <h1 class="pf-hero__title"> ... </h1>
   *       <p class="pf-hero__lede"> ... </p>
   *       <div class="pf-hero__actions"> ... </div>
   *     </div>
   *     <div class="pf-hero__media"> ... </div>
   *   </div>
   * </section>
   *
   * Variants: --split (copy + media)  --center (one column)  --photo (image bg)
   *
   * The triangle mesh is a masked pseudo-element, not an image: no extra
   * request, and it recolours with the theme because the SVG is a data URI
   * built from the accent. The mask fades it out before it reaches the copy,
   * which is what keeps the headline legible without a scrim.
   *
   * For --photo, set the image on the section itself:
   *   <section class="pf-hero pf-hero--photo" style="--pf-hero-image: url(/x.jpg)">
   */
  
  .pf-hero {
    position: relative;
    overflow: hidden;
    background: var(--pf-bg);
    padding-block: clamp(5.5rem, 13vw, 11rem);
  }
  .pf-hero::before {
    content: "";
    position: absolute;
    inset: -20% -10% auto;
    height: 150%;
    background-image: var(--pf-mesh);
    background-position: center top;
    -webkit-mask-image: radial-gradient(120% 80% at 78% 0%, #000 0%, transparent 68%);
    mask-image: radial-gradient(120% 80% at 78% 0%, #000 0%, transparent 68%);
    pointer-events: none;
  }
  .pf-hero > * { position: relative; }
  
  .pf-hero__inner { display: grid; gap: var(--pf-space-5); }
  .pf-hero--center .pf-hero__inner { justify-items: center; text-align: center; }
  .pf-hero--center .pf-hero__lede { margin-inline: auto; }
  
  .pf-hero__eyebrow {
    display: inline-flex;
    align-items: center;
    gap: var(--pf-space-2);
    background: var(--pf-surface);
    border: 1px solid var(--pf-border);
    border-radius: var(--pf-radius-pill);
    color: var(--pf-text-muted);
    font-size: var(--pf-text-xs);
    padding: 0.45rem 0.95rem;
    width: fit-content;
  }
  
  .pf-hero__title {
    font-size: var(--pf-text-5xl);
    line-height: var(--pf-leading-tight);
    letter-spacing: -0.038em;
    max-width: 15ch;
  }
  .pf-hero--center .pf-hero__title { max-width: 20ch; }
  
  .pf-hero__lede {
    color: var(--pf-text-muted);
    font-size: var(--pf-text-xl);
    line-height: 1.55;
    max-width: 52ch;
  }
  
  .pf-hero__actions { display: flex; flex-wrap: wrap; gap: var(--pf-space-3); margin-top: var(--pf-space-2); }
  
  .pf-hero__meta {
    display: flex;
    flex-wrap: wrap;
    gap: var(--pf-space-2) var(--pf-space-5);
    margin-top: var(--pf-space-4);
    color: var(--pf-text-muted);
    font-size: var(--pf-text-sm);
  }
  .pf-hero__meta li { display: flex; align-items: center; gap: 0.5rem; }
  
  /* Split hero: copy left, artwork or code sample right. */
  .pf-hero--split .pf-hero__inner {
    grid-template-columns: repeat(auto-fit, minmax(min(400px, 100%), 1fr));
    gap: var(--pf-gap-lg);
    align-items: center;
  }
  .pf-hero__media {
    border: 1px solid var(--pf-border);
    border-radius: var(--pf-radius-lg);
    background: var(--pf-base-900);
    overflow: hidden;
    box-shadow: var(--pf-lift);
  }
  .pf-hero__media img { width: 100%; }
  
  /**
   * The ::after gradient sits at z-index 0 and the hero's children are lifted to
   * 1. Without that explicit lift the pseudo-element paints over the copy,
   * because positioned siblings paint in document order and ::after comes last.
   */
  .pf-hero--photo { --pf-hero-image: none; }
  .pf-hero--photo::after {
    content: "";
    position: absolute;
    inset: 0;
    background-image: linear-gradient(to right, var(--pf-base-800) 12%, rgba(0, 15, 63, 0.72) 55%, rgba(0, 8, 35, 0.85)),
      var(--pf-hero-image);
    background-size: cover;
    background-position: center;
    z-index: 0;
  }
  .pf-hero--photo > * { z-index: 1; }
  
  /* ==========================================================================
     #PAGE HEADER + BREADCRUMBS
     ========================================================================== */
  
  /**
   * Page header
   *
   * <div class="pf-pagehead">
   *   <div class="pf-container pf-pagehead__inner">
   *     <ul class="pf-breadcrumb"> ... </ul>
   *     <h1 class="pf-pagehead__title"> ... </h1>
   *     <p class="pf-pagehead__lede"> ... </p>
   *   </div>
   * </div>
   *
   * Shorter than a hero, because the visitor has already arrived. The
   * breadcrumb separator is a ::before on each item after the first, so it is
   * never selected when the text is copied.
   */
  
  .pf-pagehead {
    border-bottom: 1px solid var(--pf-border);
    padding-block: clamp(4rem, 8vw, 6.5rem);
    background: linear-gradient(var(--pf-base-900), var(--pf-bg));
  }
  .pf-pagehead__inner { display: grid; gap: var(--pf-space-3); }
  .pf-pagehead__title { font-size: var(--pf-text-4xl); max-width: 18ch; }
  .pf-pagehead__lede { color: var(--pf-text-muted); font-size: var(--pf-text-lg); line-height: 1.6; max-width: 58ch; }
  
  .pf-breadcrumb {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--pf-space-2);
    color: var(--pf-text-muted);
    font-size: var(--pf-text-sm);
    margin: 0;
  }
  .pf-breadcrumb li { display: flex; align-items: center; gap: var(--pf-space-2); }
  .pf-breadcrumb li + li::before { content: "/"; color: rgba(169, 188, 216, 0.5); }
  .pf-breadcrumb a { text-decoration: none; }
}

/* ===== PolyFishCSS-Content.css ===== */
/*! PolyFishCSS-Content.css | v1.0.0-rc.2-rc.1-rc.1-rc.1-rc.1-rc.1 | polyfish.org | MIT
 *
 * The body of a page: sections, cards, feature and pricing grids, stats,
 * tables, alerts, code blocks, forms, accordions, sidebar navigation,
 * galleries, steps and closing CTA bands. The largest module, and the one
 * most pages need.
 *
 * Depends on: PolyFishCSS-Core.css.
 * Load order: Core -> Headers -> Content -> Footers -> Utilities.
 *
 * CONTENTS
 *   1. Sections
 *   2. Cards
 *   3. Pricing / plan cards
 *   4. Stats
 *   5. Tables
 *   6. Alerts and notes
 *   7. Code
 *   8. Forms
 *   9. Accordion
 *   10. Sidebar navigation
 *   11. Gallery tiles
 *   12. Steps
 *   13. CTA band
 *
 * CONVENTIONS
 *   .pf-block / .pf-block__element / .pf-block--modifier.
 *   Components read role tokens, never palette values. See docs/tokens.
 *
 * NO BEHAVIOUR
 *   Nothing here needs JavaScript. The accordion is a native <details>, the
 *   tables scroll rather than collapse, and the forms are styled controls, not
 *   replacements for them. If a component would need state, it is not in this
 *   file - that is the line the framework holds.
 */

@layer polyfish.core, polyfish.grid, polyfish.headers, polyfish.content, polyfish.forms, polyfish.components, polyfish.footers, polyfish.space, polyfish.effects, polyfish.utilities, polyfish.fonts, polyfish.compat;

/* ==========================================================================
   CASCADE LAYER
   ==========================================================================
   Everything below sits in `polyfish.content`. The layer order is declared in
   every module, so it holds no matter which order you link the files in.

   Why this matters to you: unlayered CSS beats layered CSS regardless of
   specificity. Your own stylesheet overrides any framework rule with a plain
   class selector — no `!important`, no specificity arms race, no worrying
   about whether Utilities loaded last.

     <link rel="stylesheet" href="PolyFishCSS-Core.min.css">
     <link rel="stylesheet" href="my-app.css">   <!-- wins, always -->

   If you want your CSS layered too, name a layer after the framework's:

     @layer polyfish, app;
     @layer app { .card { background: rebeccapurple; } }
   ========================================================================== */

@layer polyfish.content {
  /* ==========================================================================
     #SECTIONS
     ========================================================================== */
  
  /**
   * Section
   *
   * <section class="pf-section pf-section--roomy">
   *   <div class="pf-container">
   *     <div class="pf-section__head">
   *       <p class="pf-eyebrow"><span class="pf-mark"></span> Label</p>
   *       <h2>Heading</h2>
   *       <p class="pf-lede">One line of context.</p>
   *     </div>
   *     ...
   *   </div>
   * </section>
   *
   * Variants: --tight  --roomy  --vast  --alt (deep bg)  --raised (surface bg)
   *
   * Vertical rhythm is a token, not a hardcoded clamp: each variant simply
   * redeclares --pf-section-pad, so a page's whole rhythm can be shifted by
   * setting that property once on a wrapper. Adjacent sections get a hairline
   * rule between them, which is why --alt reads as a band rather than a box.
   */
  
  .pf-section { padding-block: var(--pf-section-pad); }
  .pf-section.pf-section--tight { --pf-section-pad: clamp(2rem, 4vw, 3rem); }
  /* Give a section room to breathe. Use --roomy for a whole page's rhythm and
     --vast for the one or two sections that carry the argument. */
  .pf-section.pf-section--roomy { --pf-section-pad: clamp(4.5rem, 11vw, 9rem); }
  .pf-section.pf-section--vast { --pf-section-pad: clamp(6rem, 16vw, 13rem); }
  .pf-section.pf-section--alt { background: var(--pf-base-900); }
  .pf-section.pf-section--raised { background: var(--pf-surface); }
  .pf-section + .pf-section { border-top: 1px solid var(--pf-border); }
  
  .pf-section__head {
    display: grid;
    gap: var(--pf-space-3);
    margin-bottom: var(--pf-section-head-gap, var(--pf-gap-lg));
    max-width: 62ch;
  }
  .pf-section__head--center { margin-inline: auto; justify-items: center; text-align: center; }
  .pf-section--roomy > * > .pf-section__head,
  .pf-section--vast > * > .pf-section__head { --pf-section-head-gap: var(--pf-space-8); }
  
  /**
   * Eyebrow
   *
   * Sentence case with a small triangle, rather than the tracked-out capitals
   * every SaaS page uses. Caps at 12px are measurably slower to read and the
   * marker does the same job of signalling "label, not heading".
   */
  .pf-eyebrow {
    display: inline-flex;
    align-items: center;
    gap: var(--pf-space-2);
    color: var(--pf-accent);
    font-family: var(--pf-font-mono);
    font-size: var(--pf-text-sm);
    font-weight: 500;
  }
  
  .pf-lede {
    color: var(--pf-text-muted);
    font-size: var(--pf-text-xl);
    line-height: 1.55;
    max-width: 58ch;
  }
  .pf-muted { color: var(--pf-text-muted); }
  
  /**
   * Prose rhythm.
   *
   * Long-form pages were relying on default paragraph margins, which are
   * tighter than the rest of the framework's spacing and made documentation
   * feel cramped next to the marketing pages. This sets the vertical rhythm
   * from the space scale like everything else.
   */
  .pf-prose > * + * { margin-top: var(--pf-space-5); }
  .pf-prose > h2 { margin-top: var(--pf-space-8); }
  .pf-prose > h3 { margin-top: var(--pf-space-7); }
  .pf-prose > h2 + *,
  .pf-prose > h3 + * { margin-top: var(--pf-space-4); }
  .pf-prose > hr { margin-block: var(--pf-space-8); }
  .pf-prose > .pf-table-wrap,
  .pf-prose > .pf-code,
  .pf-prose > .pf-alert { margin-top: var(--pf-space-6); }
  
  /* ==========================================================================
     #CARDS
     ========================================================================== */
  
  /**
   * Card
   *
   * <article class="pf-card pf-card--facet">
   *   <span class="pf-card__icon">01</span>
   *   <h3 class="pf-card__title">Title</h3>
   *   <p class="pf-card__body">Body copy.</p>
   *   <div class="pf-card__foot"> ... </div>
   * </article>
   *
   * Variants: --facet (clipped corner)  --accent  --flat  --link
   *
   * The card is a flex column so __foot can take margin-top:auto and pin itself
   * to the bottom, which is what keeps a row of cards with uneven copy from
   * ending on ragged buttons.
   *
   * --link turns the whole card into an anchor. Put the <a> on the card itself
   * rather than nesting one inside: nested interactive elements are invalid and
   * make the card a keyboard trap of two tab stops for one destination.
   */
  
  .pf-card {
    display: flex;
    flex-direction: column;
    gap: var(--pf-space-3);
    /* Padding scales with the viewport: 20px on a phone where every pixel of
       line length counts, 32px on a desktop where air is the point. */
    background: var(--pf-surface);
    border: 1px solid var(--pf-border);
    border-radius: var(--pf-radius-lg);
    padding: clamp(1.5rem, 3vw, 2.5rem);
    transition: border-color var(--pf-speed) var(--pf-ease), background-color var(--pf-speed) var(--pf-ease);
  }
  .pf-card__title { font-size: var(--pf-text-xl); line-height: 1.25; }
  .pf-card__body { color: var(--pf-text-muted); line-height: 1.65; }
  .pf-card__foot { margin-top: auto; padding-top: var(--pf-space-4); }
  .pf-card > p { max-width: none; }
  
  .pf-card--facet {
    border-radius: var(--pf-radius);
    clip-path: polygon(0 0, calc(100% - var(--pf-cut)) 0, 100% var(--pf-cut), 100% 100%, 0 100%);
  }
  .pf-card--accent { border-color: var(--pf-border-strong); background: var(--pf-hue-1-wash); }
  .pf-card--flat { background: none; }
  .pf-card--link { text-decoration: none; color: inherit; }
  .pf-card--link:hover { border-color: var(--pf-border-strong); background: var(--pf-surface-raised); color: inherit; }
  
  .pf-card__icon {
    display: grid;
    place-items: center;
    width: 2.6rem;
    height: 2.6rem;
    background: var(--pf-hue-1-wash);
    border: 1px solid rgba(143, 224, 106, 0.3);
    border-radius: var(--pf-radius);
    color: var(--pf-accent);
    font-family: var(--pf-font-mono);
    font-size: var(--pf-text-sm);
  }
  .pf-card__icon--accent-2 {
    background: var(--pf-hue-2-wash);
    border-color: rgba(229, 177, 137, 0.3);
    color: var(--pf-accent-2);
  }
  
  /* Feature list — compact, icon optional */
  .pf-feature { display: grid; gap: var(--pf-space-2); }
  .pf-feature h3 { font-size: var(--pf-text-lg); }
  .pf-feature p { color: var(--pf-text-muted); font-size: var(--pf-text-base); line-height: 1.6; max-width: 46ch; }
  
  /**
   * Checklist
   *
   * <ul class="pf-checks">
   *   <li>An item</li>
   * </ul>
   *
   * Two-column grid per item so the marker stays put and wrapped lines align to
   * the text, not under the bullet. The marker is a clipped triangle rather
   * than a character, so it never renders as a missing glyph.
   */
  .pf-checks { display: grid; gap: var(--pf-space-2); margin: 0; }
  .pf-checks li {
    display: grid;
    grid-template-columns: 1.1rem 1fr;
    gap: var(--pf-space-3);
    align-items: start;
    color: var(--pf-text-muted);
    font-size: var(--pf-text-base);
    line-height: 1.6;
  }
  .pf-checks li::before {
    content: "";
    width: 0.7rem;
    height: 0.7rem;
    margin-top: 0.45em;
    background: var(--pf-accent);
    clip-path: polygon(50% 0, 100% 100%, 0 100%);
  }
  .pf-checks--accent-2 li::before { background: var(--pf-accent-2); }
  .pf-checks--muted li::before { background: var(--pf-text-muted); }
  
  /* ==========================================================================
     #PLAN CARDS
     ========================================================================== */
  
  /**
   * Plan card
   *
   * <article class="pf-plan pf-plan--featured">
   *   <span class="pf-plan__badge">Most picked</span>
   *   <h3 class="pf-plan__name">Team</h3>
   *   <p class="pf-plan__price">$49 <span>per month</span></p>
   *   <ul class="pf-checks"> ... </ul>
   *   <div class="pf-plan__foot"> ... </div>
   * </article>
   *
   * The featured variant is a border and a gradient wash, not a scale
   * transform: growing the middle card breaks the shared baseline and makes the
   * other two look like mistakes.
   */
  
  .pf-plan {
    position: relative;
    display: flex;
    flex-direction: column;
    gap: var(--pf-space-4);
    background: var(--pf-surface);
    border: 1px solid var(--pf-border);
    border-radius: var(--pf-radius-lg);
    padding: clamp(1.75rem, 3.5vw, 3rem) clamp(1.5rem, 3vw, 2.5rem);
  }
  .pf-plan--featured {
    border-color: var(--pf-accent);
    background: linear-gradient(180deg, var(--pf-hue-1-wash), transparent 55%), var(--pf-surface);
  }
  .pf-plan__name { font-size: var(--pf-text-lg); }
  .pf-plan__note { color: var(--pf-text-muted); font-size: var(--pf-text-sm); }
  .pf-plan__price {
    display: flex;
    align-items: baseline;
    gap: 0.35rem;
    font-family: var(--pf-font-display);
    font-size: var(--pf-text-3xl);
    font-weight: 700;
    letter-spacing: -0.03em;
  }
  .pf-plan__price span { color: var(--pf-text-muted); font-family: var(--pf-font-body); font-size: var(--pf-text-sm); font-weight: 400; }
  .pf-plan__badge {
    position: absolute;
    top: var(--pf-space-4);
    inset-inline-end: var(--pf-space-4);
    background: var(--pf-accent);
    border-radius: var(--pf-radius-pill);
    color: var(--pf-base-950);
    font-size: var(--pf-text-xs);
    font-weight: 600;
    padding: 0.25rem 0.7rem;
  }
  .pf-plan__foot { margin-top: auto; padding-top: var(--pf-space-2); }
  
  /* ==========================================================================
     #STATS
     ========================================================================== */
  
  /**
   * Stat row
   *
   * <ul class="pf-stats">
   *   <li class="pf-stat">
   *     <span class="pf-stat__value">99.98%</span>
   *     <span class="pf-stat__label">Availability</span>
   *   </li>
   * </ul>
   *
   * A rule on the left rather than a box around each figure: four bordered
   * cards in a row read as navigation, four rules read as one set of numbers.
   * Auto-fit means three stats and five stats both look deliberate.
   */
  
  .pf-stats {
    display: grid;
    gap: var(--pf-gap);
    grid-template-columns: repeat(auto-fit, minmax(min(180px, 100%), 1fr));
    margin: 0;
  }
  .pf-stat { display: grid; gap: 0.15rem; border-inline-start: 2px solid var(--pf-border-strong); padding-inline-start: var(--pf-space-4); }
  .pf-stat__value {
    font-family: var(--pf-font-display);
    font-size: var(--pf-text-3xl);
    font-weight: 700;
    letter-spacing: -0.03em;
    line-height: 1;
  }
  .pf-stat__label { color: var(--pf-text-muted); font-size: var(--pf-text-sm); }
  
  /* ==========================================================================
     #TABLES
     ========================================================================== */
  
  /**
   * Table
   *
   * <div class="pf-table-wrap">
   *   <table class="pf-table pf-table--zebra">
   *     <thead><tr><th scope="col">Header</th></tr></thead>
   *     <tbody><tr><th scope="row">Row</th><td data-pf="yes">Value</td></tr></tbody>
   *   </table>
   * </div>
   *
   * The wrapper is required: it is what makes a wide table scroll horizontally
   * instead of squeezing columns into unreadable slivers on a phone. min-width
   * on the table is what forces that scroll rather than allowing the squeeze.
   *
   * data-pf="yes" / "no" colours a cell without inventing a class per state,
   * which keeps comparison tables from sprouting a dozen modifiers.
   *
   * Always use scope on header cells. It costs nothing and it is the difference
   * between a screen reader announcing a table and reading a wall of numbers.
   */
  
  .pf-table-wrap {
    overflow-x: auto;
    border: 1px solid var(--pf-border);
    border-radius: var(--pf-radius);
  }
  .pf-table { font-size: var(--pf-text-base); line-height: 1.55; min-width: 34rem; }
  .pf-table th,
  .pf-table td { padding: 0.85rem 1rem; text-align: start; vertical-align: top; }
  .pf-table thead th {
    background: var(--pf-base-900);
    color: var(--pf-base-50);
    font-family: var(--pf-font-body);
    font-size: var(--pf-text-xs);
    font-weight: 600;
    white-space: nowrap;
  }
  .pf-table tbody tr + tr { border-top: 1px solid var(--pf-border); }
  .pf-table tbody td { color: var(--pf-text-muted); }
  .pf-table tbody th { font-weight: 500; }
  .pf-table--zebra tbody tr:nth-child(even) { background: rgba(255, 255, 255, 0.03); }
  
  /* Density, borders and interaction. --hover is for tables whose rows lead
     somewhere; on a static table it promises a click that never happens. */
  .pf-table--compact th,
  .pf-table--compact td { padding: 0.5rem 0.7rem; font-size: var(--pf-text-xs); }
  .pf-table--roomy th,
  .pf-table--roomy td { padding: 1.1rem 1.25rem; }
  .pf-table--bordered th,
  .pf-table--bordered td { border: 1px solid var(--pf-border); }
  .pf-table--hover tbody tr:hover { background: var(--pf-surface-raised); }
  .pf-table--fixed { table-layout: fixed; }
  
  /* Sticky header for long tables. The wrapper needs a max-height for this to
     do anything - without a scroll container there is nothing to stick to. */
  .pf-table-wrap--tall { max-height: 26rem; overflow: auto; }
  .pf-table--sticky thead th {
    position: sticky;
    top: 0;
    z-index: 1;
  }
  /**
   * Stacking table
   *
   * <table class="pf-table pf-table--stack">
   *   <thead><tr><th>Check</th><th>Status</th></tr></thead>
   *   <tbody>
   *     <tr>
   *       <th scope="row" data-pf-label="Check">api-gateway</th>
   *       <td data-pf-label="Status">Healthy</td>
   *     </tr>
   *   </tbody>
   * </table>
   *
   * Below 620px each row becomes a card and each cell shows its column name
   * from data-pf-label. The alternative is horizontal scrolling, which works
   * but makes a six-column table genuinely tedious on a phone.
   *
   * Use it when rows are records to read. Keep the scrolling wrapper when the
   * table is a grid to compare across - stacking destroys column alignment,
   * which is the entire point of a comparison table.
   *
   * The header row is hidden with the same technique as .pf-visually-hidden
   * rather than display:none, so the column names stay in the accessibility
   * tree and the table is still announced as a table.
   */
  @media (max-width: 620px) {
    .pf-table--stack,
    .pf-table--stack tbody,
    .pf-table--stack tr,
    .pf-table--stack td,
    .pf-table--stack th { display: block; }
  
    .pf-table--stack { min-width: 0; }
  
    .pf-table--stack thead {
      position: absolute;
      width: 1px;
      height: 1px;
      overflow: hidden;
      clip-path: inset(50%);
      white-space: nowrap;
    }
  
    .pf-table--stack tbody tr {
      border: 1px solid var(--pf-border);
      border-radius: var(--pf-radius);
      margin-bottom: var(--pf-space-3);
      padding: var(--pf-space-2) var(--pf-space-4);
    }
    .pf-table--stack tbody tr + tr { border-top: 1px solid var(--pf-border); }
  
    .pf-table--stack tbody th,
    .pf-table--stack tbody td {
      display: flex;
      justify-content: space-between;
      gap: var(--pf-space-4);
      padding-inline: 0;
      text-align: end;
    }
    .pf-table--stack tbody th { text-align: end; }
  
    .pf-table--stack tbody [data-pf-label]::before {
      content: attr(data-pf-label);
      color: var(--pf-text-muted);
      font-size: var(--pf-text-xs);
      font-weight: 500;
      text-align: start;
      padding-inline-end: var(--pf-space-3);
    }
  
    .pf-table--stack tbody td + td,
    .pf-table--stack tbody th + td { border-top: 1px solid var(--pf-border); }
  }
  
  .pf-table caption {
    caption-side: bottom;
    color: var(--pf-text-muted);
    font-size: var(--pf-text-xs);
    padding-top: var(--pf-space-3);
    text-align: start;
  }
  .pf-table td[data-pf="yes"] { color: var(--pf-accent); }
  .pf-table td[data-pf="no"] { color: rgba(169, 188, 216, 0.55); }
  
  /* ==========================================================================
     #ALERTS AND QUOTES
     ========================================================================== */
  
  /**
   * Alert
   *
   * <div class="pf-alert pf-alert--warn">
   *   <p class="pf-alert__title">Careful</p>
   *   <p>What to do about it.</p>
   * </div>
   *
   * Variants: --info  --success  --warn  --danger
   *
   * Colour is carried by a left rule and a wash rather than a filled block, so
   * an alert can sit inside prose without shouting. Nothing here conveys
   * meaning by colour alone - the title does that - which is what keeps the
   * component usable for colour-blind readers.
   */
  
  .pf-alert {
    display: grid;
    gap: var(--pf-space-2);
    background: var(--pf-surface);
    border: 1px solid var(--pf-border);
    border-inline-start: 3px solid var(--pf-accent);
    border-radius: var(--pf-radius);
    padding: var(--pf-space-4) var(--pf-space-5);
    font-size: var(--pf-text-base);
  }
  .pf-alert__title { font-family: var(--pf-font-body); font-size: var(--pf-text-base); font-weight: 600; color: var(--pf-text); }
  .pf-alert p { color: var(--pf-text-muted); line-height: 1.65; max-width: none; }
  .pf-alert--info { border-left-color: var(--pf-base-600); }
  .pf-alert--success { border-left-color: var(--pf-hue-1-deep); background: var(--pf-hue-1-wash); }
  .pf-alert--warn { border-left-color: var(--pf-hue-2); background: var(--pf-hue-2-wash); }
  .pf-alert--danger { border-left-color: #e08f8f; background: rgba(224, 143, 143, 0.1); }
  
  .pf-quote {
    border-inline-start: 2px solid var(--pf-accent-2);
    padding-inline-start: var(--pf-space-5);
    font-size: var(--pf-text-lg);
    line-height: 1.5;
  }
  .pf-quote footer { color: var(--pf-text-muted); font-size: var(--pf-text-sm); margin-top: var(--pf-space-3); }
  
  /* ==========================================================================
     #CODE
     ========================================================================== */
  
  /**
   * Code block
   *
   * <div class="pf-code">
   *   <div class="pf-code__bar"><span>file.html</span><span>html</span></div>
   *   <pre><code><span class="pf-tag">&lt;div&gt;</span></code></pre>
   * </div>
   *
   * Highlighting classes (.pf-tag, .pf-attr, .pf-str, .pf-comment) are applied
   * by hand or by whatever highlighter you already run. The framework ships the
   * four colours and no tokeniser, because shipping one would mean shipping
   * JavaScript.
   */
  
  .pf-code {
    background: var(--pf-base-900);
    border: 1px solid var(--pf-border);
    border-radius: var(--pf-radius);
    overflow: hidden;
  }
  .pf-code__bar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--pf-space-3);
    background: rgba(255, 255, 255, 0.04);
    border-bottom: 1px solid var(--pf-border);
    color: var(--pf-text-muted);
    font-family: var(--pf-font-mono);
    font-size: var(--pf-text-xs);
    padding: 0.5rem 0.9rem;
  }
  /**
   * Copy button and sortable header
   *
   * Both elements are created by polyfish.js, not by you. They are styled here
   * so the optional script never has to inject styles - a script that writes
   * CSS is a script that fights your Content-Security-Policy.
   *
   * Without the script neither element exists, and nothing looks unfinished.
   */
  .pf-code__copy {
    background: var(--pf-surface-raised);
    border: 1px solid var(--pf-border);
    border-radius: var(--pf-radius-sm);
    color: var(--pf-text-muted);
    cursor: pointer;
    font-family: var(--pf-font-body);
    font-size: var(--pf-text-xs);
    padding: 0.2rem 0.6rem;
    min-height: 1.75rem;
  }
  .pf-code__copy:hover { border-color: var(--pf-border-strong); color: var(--pf-text); }
  
  .pf-th-sort {
    display: inline-flex;
    align-items: center;
    gap: 0.4em;
    background: none;
    border: 0;
    color: inherit;
    cursor: pointer;
    font: inherit;
    padding: 0;
  }
  .pf-th-sort::after {
    content: "";
    width: 0.5em;
    height: 0.5em;
    background: currentColor;
    opacity: 0.35;
    clip-path: polygon(50% 0, 100% 100%, 0 100%);
  }
  [aria-sort="ascending"] .pf-th-sort::after { opacity: 1; }
  [aria-sort="descending"] .pf-th-sort::after { opacity: 1; transform: rotate(180deg); }
  
  .pf-code pre {
    margin: 0;
    overflow-x: auto;
    padding: var(--pf-space-4) var(--pf-space-5);
    line-height: 1.7;
    tab-size: 2;
  }
  .pf-code code { color: var(--pf-base-50); font-size: var(--pf-text-sm); }
  .pf-code .pf-tag { color: var(--pf-accent); }
  .pf-code .pf-attr { color: var(--pf-accent-2); }
  .pf-code .pf-str { color: #d9e4ff; }
  .pf-code .pf-comment { color: rgba(169, 188, 216, 0.65); }
  
  /* ==========================================================================
     #FORMS
     ========================================================================== */
  
  /**
   * Field
   *
   * <div class="pf-field">
   *   <label class="pf-label" for="email">Email</label>
   *   <input class="pf-input" id="email" type="email">
   *   <p class="pf-help">Where the receipt goes.</p>
   * </div>
   *
   * Every control needs a real <label for>. Placeholder text is not a label: it
   * disappears on focus, fails contrast in most palettes, and is invisible to
   * anyone using autofill.
   *
   * The select arrow is two linear-gradients rather than a background image, so
   * it needs no asset and recolours with the accent. appearance:none removes
   * the native control, which is why the focus ring is reinstated explicitly
   * below - remove that and keyboard users lose the only focus indicator.
   *
   * Mark invalid fields with aria-invalid="true"; the styling hangs off the
   * attribute so assistive tech and the visual state stay in sync.
   */
  
  .pf-field { display: grid; gap: var(--pf-space-2); }
  .pf-label { font-size: var(--pf-text-base); font-weight: 500; }
  .pf-help { color: var(--pf-text-muted); font-size: var(--pf-text-sm); line-height: 1.5; }
  
  .pf-input,
  .pf-select,
  .pf-textarea {
    width: 100%;
    background: var(--pf-base-900);
    border: 1px solid var(--pf-border);
    border-radius: var(--pf-radius);
    color: var(--pf-text);
    font-size: var(--pf-text-sm);
    padding: 0.75rem 0.9rem;
    transition: border-color var(--pf-speed) var(--pf-ease), box-shadow var(--pf-speed) var(--pf-ease);
  }
  .pf-input::placeholder,
  .pf-textarea::placeholder { color: rgba(169, 188, 216, 0.6); }
  .pf-input:focus,
  .pf-select:focus,
  .pf-textarea:focus {
    border-color: var(--pf-accent);
    box-shadow: var(--pf-ring);
    outline: none;
  }
  .pf-textarea { min-height: 8rem; resize: vertical; }
  .pf-select {
    appearance: none;
    background-image: linear-gradient(45deg, transparent 50%, var(--pf-accent) 50%),
      linear-gradient(135deg, var(--pf-accent) 50%, transparent 50%);
    background-position: right 1.1rem center, right 0.75rem center;
    background-size: 6px 6px, 6px 6px;
    background-repeat: no-repeat;
    padding-inline-end: 2.4rem;
  }
  .pf-input[aria-invalid="true"],
  .pf-textarea[aria-invalid="true"] { border-color: #e08f8f; }
  
  .pf-choice { display: flex; align-items: center; gap: var(--pf-space-3); font-size: var(--pf-text-sm); }
  .pf-choice input { accent-color: var(--pf-hue-1); width: 1.05rem; height: 1.05rem; }
  
  .pf-inline-form {
    display: flex;
    flex-wrap: wrap;
    gap: var(--pf-space-2);
  }
  .pf-inline-form .pf-input { flex: 1 1 14rem; width: auto; }
  
  /* ==========================================================================
     #ACCORDION
     ========================================================================== */
  
  /**
   * Accordion
   *
   * <div class="pf-accordion">
   *   <details open>
   *     <summary>Question</summary>
   *     <p>Answer.</p>
   *   </details>
   * </div>
   *
   * Native <details>, so open state, keyboard handling and find-in-page all
   * work for free, and the content prints expanded. The default marker is
   * removed twice - list-style on summary and the WebKit pseudo-element - which
   * is the pair you need for cross-browser removal.
   */
  
  .pf-accordion { display: grid; gap: var(--pf-space-2); }
  .pf-accordion details {
    background: var(--pf-surface);
    border: 1px solid var(--pf-border);
    border-radius: var(--pf-radius);
    padding: var(--pf-space-4) var(--pf-space-5);
  }
  .pf-accordion summary {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--pf-space-4);
    cursor: pointer;
    font-family: var(--pf-font-display);
    font-size: var(--pf-text-lg);
    font-weight: 600;
    list-style: none;
  }
  .pf-accordion summary::-webkit-details-marker { display: none; }
  .pf-accordion summary::after {
    content: "";
    width: 0.75rem;
    height: 0.75rem;
    flex: none;
    background: var(--pf-accent);
    clip-path: polygon(50% 100%, 0 0, 100% 0);
    transition: transform var(--pf-speed) var(--pf-ease);
  }
  .pf-accordion details[open] summary::after { transform: rotate(180deg); }
  .pf-accordion details[open] summary { margin-bottom: var(--pf-space-3); }
  .pf-accordion p { color: var(--pf-text-muted); font-size: var(--pf-text-base); line-height: 1.65; }
  
  /**
   * Sidebar navigation
   *
   * <aside class="pf-sidenav pf-sidenav--sticky">
   *   <div class="pf-sidenav__group">
   *     <h2 class="pf-sidenav__heading">Section</h2>
   *     <ul class="pf-sidenav__links"> ... </ul>
   *   </div>
   * </aside>
   *
   * Pair it with a two-column .pf-grid. --sticky needs an ancestor that does
   * not clip overflow, which is the usual reason a sticky sidebar silently
   * refuses to stick.
   */
  .pf-sidenav { display: grid; gap: var(--pf-space-5); align-content: start; }
  .pf-sidenav--sticky { position: sticky; top: 6rem; }
  .pf-sidenav__group { display: grid; gap: var(--pf-space-2); }
  .pf-sidenav__heading {
    font-family: var(--pf-font-body);
    font-size: var(--pf-text-sm);
    font-weight: 600;
    color: var(--pf-text);
  }
  .pf-sidenav__links { display: grid; gap: var(--pf-space-2); margin: 0; }
  .pf-sidenav__links a {
    color: var(--pf-text-muted);
    font-size: var(--pf-text-base);
    text-decoration: none;
  }
  .pf-sidenav__links a:hover { color: var(--pf-accent); }
  .pf-sidenav__links a[aria-current] { color: var(--pf-base-50); }
  
  /* ==========================================================================
     #GALLERY
     ========================================================================== */
  
  /**
   * Tile
   *
   * <figure class="pf-tile">
   *   <img src="..." alt="Describe the image, or leave alt empty if decorative">
   *   <figcaption>Caption</figcaption>
   * </figure>
   *
   * aspect-ratio holds the grid steady before images load, which is most of the
   * layout shift on an image-heavy page. object-fit:cover then crops rather
   * than distorting whatever you supply.
   */
  
  .pf-gallery {
    display: grid;
    gap: var(--pf-space-4);
    grid-template-columns: repeat(auto-fit, minmax(min(220px, 100%), 1fr));
    margin: 0;
  }
  .pf-tile {
    position: relative;
    overflow: hidden;
    border: 1px solid var(--pf-border);
    border-radius: var(--pf-radius);
    aspect-ratio: 4 / 3;
    background: var(--pf-base-900);
  }
  .pf-tile img { width: 100%; height: 100%; object-fit: cover; }
  .pf-tile figcaption {
    position: absolute;
    inset: auto 0 0;
    background: linear-gradient(transparent, rgba(0, 8, 35, 0.92));
    color: var(--pf-base-50);
    font-size: var(--pf-text-sm);
    padding: var(--pf-space-5) var(--pf-space-4) var(--pf-space-3);
  }
  
  /**
   * Scroller
   *
   * <ul class="pf-scroller">
   *   <li class="pf-scroller__item"> ... </li>
   * </ul>
   *
   * A horizontally scrollable row with snap points, for card rows that would
   * otherwise stack into a very long column on a phone. This is what PolyFish
   * has instead of a carousel: no autoplay, no hidden slides, no script, and
   * the content is reachable by scrolling, keyboard and screen reader alike.
   *
   * scroll-padding matches the gutter so a snapped card is not flush to the
   * edge, and overscroll-behavior-x stops a swipe at the end of the row from
   * triggering the browser's back gesture.
   */
  .pf-scroller {
    display: grid;
    grid-auto-flow: column;
    grid-auto-columns: min(var(--pf-scroller-item, 20rem), 82%);
    gap: var(--pf-gap);
    overflow-x: auto;
    overscroll-behavior-x: contain;
    scroll-snap-type: x mandatory;
    scroll-padding-inline: var(--pf-gutter);
    padding-bottom: var(--pf-space-3);
    margin: 0;
    /* Bleed to the viewport edge on a phone so the row reads as scrollable,
       while the first card still lines up with the text above it. */
    scrollbar-width: thin;
  }
  .pf-scroller > * { scroll-snap-align: start; }
  .pf-scroller--sm { --pf-scroller-item: 14rem; }
  .pf-scroller--lg { --pf-scroller-item: 26rem; }
  
  @media (min-width: 900px) {
    /* On a wide screen there is room for the row, so stop it scrolling. */
    .pf-scroller--stop {
      grid-auto-flow: row;
      grid-template-columns: repeat(auto-fit, minmax(min(20rem, 100%), 1fr));
      overflow: visible;
    }
  }
  
  /* ==========================================================================
     #STEPS
     ========================================================================== */
  
  /**
   * Steps
   *
   * <ol class="pf-steps">
   *   <li><h3>Do this first</h3><p>Detail.</p></li>
   * </ol>
   *
   * Numbers come from a CSS counter on an <ol>, so the order is real in the
   * markup and the numbering never drifts from the source. Use this only for
   * genuine sequences; a numbered list of unordered features reads as a ranking
   * nobody intended.
   */
  
  .pf-steps { counter-reset: pf-step; display: grid; gap: var(--pf-space-7); margin: 0; }
  .pf-steps li {
    counter-increment: pf-step;
    display: grid;
    grid-template-columns: 2.2rem 1fr;
    gap: var(--pf-space-4);
    align-items: start;
    max-width: none;
  }
  /**
   * The number is the first grid item, and every real child has to be told to
   * sit in the second column. Without that, a step with a heading AND a
   * paragraph puts the paragraph on the next row in the 2.2rem number column,
   * where it wraps one character per line.
   *
   * Two children looked fine, which is why this survived: the bug only appears
   * once a step has a title and body text, and no amount of CSS parsing or
   * markup validation can see it.
   */
  .pf-steps li::before {
    grid-column: 1;
    grid-row: 1;
    content: counter(pf-step);
    display: grid;
    place-items: center;
    width: 2.2rem;
    height: 2.2rem;
    background: var(--pf-hue-1-wash);
    border: 1px solid var(--pf-border-strong);
    border-radius: var(--pf-radius-sm);
    color: var(--pf-accent);
    font-family: var(--pf-font-mono);
    font-size: var(--pf-text-sm);
  }
  .pf-steps li > * { grid-column: 2; }
  .pf-steps h3 { font-size: var(--pf-text-lg); margin-bottom: 0.25rem; }
  .pf-steps p { color: var(--pf-text-muted); font-size: var(--pf-text-base); line-height: 1.6; }
  
  /**
   * Centred screen
   *
   * <body class="pf-screen">
   *   <main class="pf-container pf-container--narrow"> ... </main>
   * </body>
   *
   * One card, vertically centred on the mesh. For sign-in, error and
   * confirmation pages that have no navigation and no footer.
   */
  .pf-screen {
    display: grid;
    place-items: center;
    min-height: 100vh;
    min-height: 100dvh;
    background-image: var(--pf-mesh);
  }
  .pf-screen__panel { width: min(26rem, 100%); }
  
  /* Surface fill for a gallery tile with no image behind it. */
  .pf-tile__fill { width: 100%; height: 100%; }
  
  /* Type specimen: display-scale text that is not a heading. */
  .pf-specimen {
    font-family: var(--pf-font-display);
    font-size: var(--pf-text-4xl);
    font-weight: 700;
    line-height: var(--pf-leading-tight);
    letter-spacing: -0.03em;
    margin: 0;
  }
  
  /* ==========================================================================
     #CTA BAND
     ========================================================================== */
  
  /**
   * CTA band
   *
   * <div class="pf-cta">
   *   <div class="pf-cta__inner">
   *     <div class="pf-stack pf-gap-3"><h2> ... </h2><p> ... </p></div>
   *     <div class="pf-cluster"> ... buttons ... </div>
   *   </div>
   * </div>
   *
   * The closing argument of a page. Same mesh as the hero, masked from the
   * opposite corner so the two do not read as the same element repeated.
   */
  
  .pf-cta {
    position: relative;
    overflow: hidden;
    background: var(--pf-base-900);
    border: 1px solid var(--pf-border-strong);
    border-radius: var(--pf-radius-lg);
    padding: clamp(2.5rem, 7vw, 5.5rem);
  }
  .pf-cta::before {
    content: "";
    position: absolute;
    inset: 0;
    background-image: var(--pf-mesh);
    -webkit-mask-image: linear-gradient(105deg, #000, transparent 62%);
    mask-image: linear-gradient(105deg, #000, transparent 62%);
    pointer-events: none;
  }
  .pf-cta__inner {
    position: relative;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: var(--pf-space-5);
  }
  .pf-cta h2 { font-size: var(--pf-text-3xl); max-width: 20ch; }
  .pf-cta p { color: var(--pf-text-muted); max-width: 44ch; }
}

/* ===== PolyFishCSS-Forms.css ===== */
/*! PolyFishCSS-Forms.css | v1.0.0-rc.2-rc.1-rc.1-rc.1-rc.1-rc.1 | polyfish.org | MIT
 *
 * Everything a real form needs beyond the four controls in Content: sizes,
 * floating labels, validation feedback, fieldsets, range and file inputs,
 * inline checks, form layout rows and character counters.
 *
 * Depends on: PolyFishCSS-Core.css and PolyFishCSS-Content.css
 *             (.pf-input, .pf-label, .pf-help, .pf-field, .pf-select).
 * Load order: after Content, before Utilities.
 *
 * CONTENTS
 *   1. Sizes
 *   2. Floating labels
 *   3. Validation states and feedback
 *   4. Fieldsets and legends
 *   5. Range
 *   6. File input
 *   7. Checks and radios
 *   8. Form layout
 *   9. Counters and hints
 *
 * THE RULE THAT MATTERS MORE THAN ANY STYLE
 *   Every control needs a programmatic name. A <label for>, or aria-label, or
 *   aria-labelledby. A placeholder is not a name: it vanishes on focus, fails
 *   contrast in most palettes and is skipped by some screen readers. The
 *   floating-label pattern below exists precisely so a form can look like it
 *   uses placeholders while actually using labels.
 */

@layer polyfish.core, polyfish.grid, polyfish.headers, polyfish.content, polyfish.forms, polyfish.components, polyfish.footers, polyfish.space, polyfish.effects, polyfish.utilities, polyfish.fonts, polyfish.compat;

/* ==========================================================================
   CASCADE LAYER
   ==========================================================================
   Everything below sits in `polyfish.forms`. The layer order is declared in
   every module, so it holds no matter which order you link the files in.

   Why this matters to you: unlayered CSS beats layered CSS regardless of
   specificity. Your own stylesheet overrides any framework rule with a plain
   class selector — no `!important`, no specificity arms race, no worrying
   about whether Utilities loaded last.

     <link rel="stylesheet" href="PolyFishCSS-Core.min.css">
     <link rel="stylesheet" href="my-app.css">   <!-- wins, always -->

   If you want your CSS layered too, name a layer after the framework's:

     @layer polyfish, app;
     @layer app { .card { background: rebeccapurple; } }
   ========================================================================== */

@layer polyfish.forms {
  /* ==========================================================================
     #SIZES
     ========================================================================== */
  
  /**
   * <input class="pf-input pf-input--sm">
   *
   * Padding is in em so a size modifier only changes font-size. Note there is
   * no size below --sm: at 12px a text field stops being comfortably tappable,
   * and Core's pointer:coarse floor would fight it anyway.
   */
  .pf-input--sm,
  .pf-select--sm { font-size: var(--pf-text-xs); padding: 0.55em 0.7em; }
  .pf-input--lg,
  .pf-select--lg { font-size: var(--pf-text-base); padding: 0.85em 1em; }
  
  /* ==========================================================================
     #FLOATING LABELS
     ========================================================================== */
  
  /**
   * Floating label
   *
   * <div class="pf-float">
   *   <input class="pf-input" id="email" type="email" placeholder=" ">
   *   <label class="pf-float__label" for="email">Email address</label>
   * </div>
   *
   * The input comes FIRST and the label second, so :placeholder-shown and
   * :focus can select the label as a sibling. The placeholder must be a single
   * space - an empty placeholder attribute counts as shown in some engines and
   * the label never lifts.
   *
   * This is a real <label for>, so the control keeps its accessible name at
   * every state. That is the entire reason to prefer it over a placeholder.
   */
  .pf-float { position: relative; }
  .pf-float .pf-input,
  .pf-float .pf-select,
  .pf-float .pf-textarea { padding-top: 1.4em; padding-bottom: 0.5em; }
  .pf-float__label {
    position: absolute;
    top: 0.85em;
    inset-inline-start: 0.95em;
    color: var(--pf-text-muted);
    font-size: var(--pf-text-sm);
    pointer-events: none;
    transform-origin: 0 0;
    transition: transform var(--pf-speed) var(--pf-ease), color var(--pf-speed) var(--pf-ease);
  }
  .pf-float .pf-input:focus + .pf-float__label,
  .pf-float .pf-input:not(:placeholder-shown) + .pf-float__label,
  .pf-float .pf-textarea:focus + .pf-float__label,
  .pf-float .pf-textarea:not(:placeholder-shown) + .pf-float__label,
  .pf-float .pf-select + .pf-float__label {
    transform: translateY(-0.7em) scale(0.78);
  }
  .pf-float .pf-input:focus + .pf-float__label,
  .pf-float .pf-textarea:focus + .pf-float__label { color: var(--pf-accent); }
  
  /* ==========================================================================
     #VALIDATION STATES AND FEEDBACK
     ========================================================================== */
  
  /**
   * Validation
   *
   * <div class="pf-field">
   *   <label class="pf-label" for="pw">Password</label>
   *   <input class="pf-input" id="pw" type="password"
   *          aria-invalid="true" aria-describedby="pw-err">
   *   <p class="pf-feedback pf-feedback--error" id="pw-err">
   *     At least twelve characters.
   *   </p>
   * </div>
   *
   * State hangs off aria-invalid, not a class, so the styling and the
   * announcement can never disagree. The message is joined to the field with
   * aria-describedby - without that a screen reader says "invalid" and never
   * says why.
   *
   * :user-invalid is used rather than :invalid deliberately. :invalid matches
   * an empty required field the moment the page loads, which paints a form red
   * before anyone has typed. :user-invalid waits until the field has been
   * interacted with.
   */
  .pf-feedback {
    display: flex;
    align-items: flex-start;
    gap: 0.45em;
    font-size: var(--pf-text-xs);
    line-height: 1.45;
  }
  .pf-feedback::before {
    content: "";
    width: 0.7em;
    height: 0.7em;
    margin-top: 0.35em;
    flex: none;
    background: currentColor;
    clip-path: polygon(50% 0, 100% 100%, 0 100%);
  }
  .pf-feedback--error { color: #e08f8f; }
  .pf-feedback--ok { color: var(--pf-accent); }
  .pf-feedback--ok::before { clip-path: circle(50%); }
  .pf-feedback--hint { color: var(--pf-text-muted); }
  .pf-feedback--hint::before { display: none; }
  
  .pf-input[aria-invalid="true"],
  .pf-select[aria-invalid="true"],
  .pf-textarea[aria-invalid="true"],
  .pf-input:user-invalid,
  .pf-textarea:user-invalid { border-color: #e08f8f; }
  
  .pf-input[aria-invalid="true"]:focus,
  .pf-input:user-invalid:focus { box-shadow: 0 0 0 3px rgba(224, 143, 143, 0.3); }
  
  .pf-input[data-pf-valid]:not([aria-invalid="true"]) { border-color: var(--pf-accent); }
  
  /* A required marker that is decorative to assistive tech - the `required`
     attribute already announces it, and "asterisk" read aloud is noise. */
  .pf-label--required::after {
    content: "*";
    color: var(--pf-accent-2);
    margin-inline-start: 0.25em;
  }
  
  /* ==========================================================================
     #FIELDSETS AND LEGENDS
     ========================================================================== */
  
  /**
   * <fieldset class="pf-fieldset">
   *   <legend class="pf-legend">Notifications</legend>
   *   ...
   * </fieldset>
   *
   * A group of radios or checkboxes needs a fieldset and legend, not a heading.
   * The legend is what associates the question with every option in the group.
   */
  .pf-fieldset {
    border: 1px solid var(--pf-border);
    border-radius: var(--pf-radius);
    padding: var(--pf-space-5);
    min-width: 0;
  }
  .pf-fieldset--plain { border: 0; padding: 0; }
  .pf-legend {
    color: var(--pf-text);
    font-family: var(--pf-font-body);
    font-size: var(--pf-text-sm);
    font-weight: 600;
    padding-inline: var(--pf-space-2);
  }
  .pf-fieldset--plain > .pf-legend { padding-inline: 0; }
  
  /* ==========================================================================
     #RANGE
     ========================================================================== */
  
  /**
   * <input class="pf-range" type="range" min="10" max="600" step="10">
   *
   * Track and thumb have to be declared per engine - there is still no
   * interoperable shorthand - so the rules are duplicated rather than combined.
   * A combined selector list would be dropped whole by any engine that does not
   * recognise one of the pseudo-elements.
   */
  .pf-range {
    width: 100%;
    height: 1.5rem;
    appearance: none;
    background: none;
    cursor: pointer;
  }
  .pf-range:focus-visible { outline: 2px solid var(--pf-focus); outline-offset: 4px; }
  
  .pf-range::-webkit-slider-runnable-track {
    height: 0.35rem;
    background: var(--pf-surface-raised);
    border-radius: var(--pf-radius-pill);
  }
  .pf-range::-moz-range-track {
    height: 0.35rem;
    background: var(--pf-surface-raised);
    border-radius: var(--pf-radius-pill);
  }
  .pf-range::-webkit-slider-thumb {
    appearance: none;
    width: 1.1rem;
    height: 1.1rem;
    margin-top: -0.375rem;
    background: var(--pf-accent);
    border: 0;
    border-radius: 50%;
  }
  .pf-range::-moz-range-thumb {
    width: 1.1rem;
    height: 1.1rem;
    background: var(--pf-accent);
    border: 0;
    border-radius: 50%;
  }
  
  /* ==========================================================================
     #FILE INPUT
     ========================================================================== */
  
  /**
   * <input class="pf-file" type="file">
   *
   * The button part is styled through ::file-selector-button rather than the
   * old trick of hiding the input behind a label. The native control keeps its
   * keyboard behaviour and its "no file chosen" text, which a fake one loses.
   */
  .pf-file {
    width: 100%;
    background: var(--pf-base-900);
    border: 1px solid var(--pf-border);
    border-radius: var(--pf-radius);
    color: var(--pf-text-muted);
    font-size: var(--pf-text-sm);
    padding: 0.5rem;
  }
  .pf-file::file-selector-button {
    margin-inline-end: 0.75rem;
    background: var(--pf-surface-raised);
    border: 1px solid var(--pf-border);
    border-radius: var(--pf-radius-sm);
    color: var(--pf-text);
    cursor: pointer;
    font: inherit;
    padding: 0.4rem 0.8rem;
  }
  .pf-file::file-selector-button:hover { border-color: var(--pf-border-strong); }
  .pf-file:focus-visible { outline: 2px solid var(--pf-focus); outline-offset: 2px; }
  
  /* ==========================================================================
     #CHECKS AND RADIOS
     ========================================================================== */
  
  /**
   * <div class="pf-checks-group">
   *   <label class="pf-choice"><input type="checkbox"> Daily</label>
   *   <label class="pf-choice"><input type="checkbox"> Weekly</label>
   * </div>
   *
   * Stack by default, inline on request. The card variant turns each option
   * into a selectable tile, which is the pattern for plan pickers.
   */
  .pf-checks-group { display: grid; gap: var(--pf-space-3); }
  .pf-checks-group--inline { display: flex; flex-wrap: wrap; gap: var(--pf-space-5); }
  
  .pf-choice-card {
    display: flex;
    align-items: flex-start;
    gap: var(--pf-space-3);
    background: var(--pf-surface);
    border: 1px solid var(--pf-border);
    border-radius: var(--pf-radius);
    cursor: pointer;
    padding: var(--pf-space-4);
    transition: border-color var(--pf-speed) var(--pf-ease), background-color var(--pf-speed) var(--pf-ease);
  }
  .pf-choice-card:hover { border-color: var(--pf-border-strong); }
  .pf-choice-card input { accent-color: var(--pf-accent); margin-top: 0.2rem; }
  .pf-choice-card:has(input:checked) {
    border-color: var(--pf-accent);
    background: var(--pf-accent-wash, rgba(143, 224, 106, 0.12));
  }
  .pf-choice-card:has(input:focus-visible) { outline: 2px solid var(--pf-focus); outline-offset: 2px; }
  .pf-choice-card__title { font-weight: 600; font-size: var(--pf-text-sm); }
  .pf-choice-card__body { color: var(--pf-text-muted); font-size: var(--pf-text-xs); }
  
  /* ==========================================================================
     #FORM LAYOUT
     ========================================================================== */
  
  /**
   * <form class="pf-form">
   *   <div class="pf-form__row pf-form__row--2"> ... two fields ... </div>
   *   <div class="pf-field"> ... </div>
   *   <div class="pf-form__actions"> ... buttons ... </div>
   * </form>
   *
   * Rows collapse to one column below 620px. The actions row aligns right on a
   * wide screen and goes full width on a narrow one, because a half-width
   * primary button on a phone is a smaller target for no reason.
   */
  .pf-form { display: grid; gap: var(--pf-space-5); }
  .pf-form__row { display: grid; gap: var(--pf-space-4); }
  .pf-form__row--2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .pf-form__row--3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .pf-form__row--split { grid-template-columns: minmax(0, 2fr) minmax(0, 1fr); }
  .pf-form__actions {
    display: flex;
    flex-wrap: wrap;
    justify-content: flex-end;
    gap: var(--pf-space-3);
  }
  
  @media (max-width: 620px) {
    .pf-form__row--2,
    .pf-form__row--3,
    .pf-form__row--split { grid-template-columns: minmax(0, 1fr); }
    .pf-form__actions > .pf-btn { flex: 1; }
  }
  
  /* Horizontal form: label beside the control, for settings screens. */
  .pf-field--horizontal {
    display: grid;
    grid-template-columns: minmax(0, 12rem) minmax(0, 1fr);
    align-items: start;
    gap: var(--pf-space-4);
  }
  .pf-field--horizontal .pf-help { grid-column: 2; }
  @media (max-width: 760px) {
    .pf-field--horizontal { grid-template-columns: minmax(0, 1fr); }
    .pf-field--horizontal .pf-help { grid-column: 1; }
  }
  
  /* ==========================================================================
     #COUNTERS AND HINTS
     ========================================================================== */
  
  /**
   * <div class="pf-field">
   *   <div class="pf-label-row">
   *     <label class="pf-label" for="bio">Bio</label>
   *     <span class="pf-counter">0 / 280</span>
   *   </div>
   *   <textarea class="pf-textarea" id="bio" maxlength="280"></textarea>
   * </div>
   *
   * The count itself needs a script - CSS cannot read a value's length. What is
   * here is the layout and the styling, so the script only has to set text.
   * Mark the counter aria-live="polite" if you update it on every keystroke.
   */
  .pf-label-row {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--pf-space-3);
  }
  .pf-counter {
    color: var(--pf-text-muted);
    font-family: var(--pf-font-mono);
    font-size: var(--pf-text-xs);
    font-variant-numeric: tabular-nums;
  }
  .pf-counter--over { color: #e08f8f; }
}

/* ===== PolyFishCSS-Components.css ===== */
/*! PolyFishCSS-Components.css | v1.0.0-rc.2-rc.1-rc.1-rc.1-rc.1-rc.1 | polyfish.org | MIT
 *
 * The interface pieces an application needs beyond a marketing page: badges,
 * button groups, pagination, progress, spinners, list groups, avatars,
 * switches, input groups, tabs, disclosure menus, dialogs, tooltips,
 * breadcrumb bars, skeletons and empty states.
 *
 * Depends on: PolyFishCSS-Core.css. Some components read Content's field
 *             styles (.pf-input) - each says so where it matters.
 * Load order: after Content, before Utilities.
 *
 * CONTENTS
 *   1.  Badges and chips
 *   2.  Button groups and split buttons
 *   3.  Pagination
 *   4.  Progress and meter
 *   5.  Spinner
 *   6.  List group
 *   7.  Avatar and avatar stack
 *   8.  Switch
 *   9.  Input group
 *   10. Tabs
 *   11. Disclosure menu
 *   12. Dialog
 *   13. Tooltip
 *   14. Ratio box
 *   15. Skeleton
 *   16. Empty state
 *   17. Divider
 *   18. Toolbar
 *
 * NO JAVASCRIPT, STILL
 *   Tabs are radio inputs. The disclosure menu is <details>. The dialog is a
 *   native <dialog> for the JavaScript case and a :target fallback for the
 *   scripted-free one. Anything that could not be done honestly without a
 *   script - a toast queue, a carousel, a combobox - is not here, because a
 *   half-working version of those is worse than none.
 */

@layer polyfish.core, polyfish.grid, polyfish.headers, polyfish.content, polyfish.forms, polyfish.components, polyfish.footers, polyfish.space, polyfish.effects, polyfish.utilities, polyfish.fonts, polyfish.compat;

/* ==========================================================================
   CASCADE LAYER
   ==========================================================================
   Everything below sits in `polyfish.components`. The layer order is declared in
   every module, so it holds no matter which order you link the files in.

   Why this matters to you: unlayered CSS beats layered CSS regardless of
   specificity. Your own stylesheet overrides any framework rule with a plain
   class selector — no `!important`, no specificity arms race, no worrying
   about whether Utilities loaded last.

     <link rel="stylesheet" href="PolyFishCSS-Core.min.css">
     <link rel="stylesheet" href="my-app.css">   <!-- wins, always -->

   If you want your CSS layered too, name a layer after the framework's:

     @layer polyfish, app;
     @layer app { .card { background: rebeccapurple; } }
   ========================================================================== */

@layer polyfish.components {
  /* ==========================================================================
     #BADGES AND CHIPS
     ========================================================================== */
  
  /**
   * Badge
   *
   * <span class="pf-badge">New</span>
   * <span class="pf-badge pf-badge--accent">12</span>
   * <a class="pf-chip" href="/tags/css">css <span class="pf-chip__x">&times;</span></a>
   *
   * Variants: --accent  --secondary  --danger  --muted  --outline
   * Sizes are inherited: the badge is sized in em, so it matches whatever text
   * it sits inside rather than needing a size modifier.
   */
  .pf-badge {
    display: inline-flex;
    align-items: center;
    gap: 0.35em;
    background: var(--pf-surface-raised);
    border: 1px solid var(--pf-border);
    border-radius: var(--pf-radius-pill);
    color: var(--pf-text);
    font-size: 0.78em;
    font-weight: 600;
    line-height: 1;
    padding: 0.35em 0.7em;
    white-space: nowrap;
  }
  .pf-badge--accent { background: var(--pf-accent); border-color: var(--pf-accent); color: var(--pf-base-950); }
  .pf-badge--secondary { background: var(--pf-accent-2); border-color: var(--pf-accent-2); color: var(--pf-base-950); }
  .pf-badge--danger { background: #e08f8f; border-color: #e08f8f; color: var(--pf-base-950); }
  .pf-badge--muted { background: transparent; color: var(--pf-text-muted); }
  .pf-badge--outline { background: transparent; border-color: var(--pf-border-strong); color: var(--pf-accent); }
  
  /* Count badge riding on a button or nav item. */
  .pf-badge--count {
    min-width: 1.5em;
    justify-content: center;
    padding-inline: 0.45em;
  }
  
  /* Removable tag. The × is a child so the whole tag stays one hit target. */
  .pf-chip {
    display: inline-flex;
    align-items: center;
    gap: 0.5em;
    background: var(--pf-surface);
    border: 1px solid var(--pf-border);
    border-radius: var(--pf-radius-sm);
    color: var(--pf-text-muted);
    font-size: var(--pf-text-sm);
    padding: 0.3em 0.6em;
    text-decoration: none;
  }
  .pf-chip:hover { border-color: var(--pf-border-strong); color: var(--pf-text); }
  .pf-chip__x { color: var(--pf-text-muted); font-size: 1.1em; line-height: 1; }
  
  /* ==========================================================================
     #BUTTON GROUPS
     ========================================================================== */
  
  /**
   * Button group
   *
   * <div class="pf-btn-group" role="group" aria-label="View">
   *   <button class="pf-btn pf-btn--secondary" type="button" aria-pressed="true">Day</button>
   *   <button class="pf-btn pf-btn--secondary" type="button">Week</button>
   * </div>
   *
   * The pill radius is flattened between members and restored at the ends, and
   * the shared border is collapsed with a negative margin so the seam is one
   * line rather than two. aria-pressed carries the selected state - it styles
   * itself, so the visual and the announced state cannot diverge.
   */
  .pf-btn-group {
    display: inline-flex;
    flex-wrap: wrap;
  }
  .pf-btn-group > .pf-btn { border-radius: 0; }
  .pf-btn-group > .pf-btn:not(:first-child) { margin-inline-start: -1.5px; }
  .pf-btn-group > .pf-btn:first-child {
    border-start-start-radius: var(--pf-radius-pill);
    border-end-start-radius: var(--pf-radius-pill);
  }
  .pf-btn-group > .pf-btn:last-child {
    border-start-end-radius: var(--pf-radius-pill);
    border-end-end-radius: var(--pf-radius-pill);
  }
  .pf-btn-group > .pf-btn:hover,
  .pf-btn-group > .pf-btn:focus-visible { position: relative; z-index: 1; }
  .pf-btn-group > .pf-btn[aria-pressed="true"] {
    background: var(--pf-accent);
    border-color: var(--pf-accent);
    color: var(--pf-base-950);
  }
  .pf-btn-group--square > .pf-btn:first-child,
  .pf-btn-group--square > .pf-btn:last-child {
    border-radius: var(--pf-radius);
  }
  .pf-btn-group--block { display: flex; }
  .pf-btn-group--block > .pf-btn { flex: 1; }
  
  /* ==========================================================================
     #PAGINATION
     ========================================================================== */
  
  /**
   * Pagination
   *
   * <nav class="pf-pagination" aria-label="Pages">
   *   <a class="pf-pagination__item" href="?p=1" rel="prev">Previous</a>
   *   <a class="pf-pagination__item" href="?p=1">1</a>
   *   <span class="pf-pagination__item" aria-current="page">2</span>
   *   <span class="pf-pagination__gap">…</span>
   * </nav>
   *
   * The current page is a <span>, not a link to itself, and carries
   * aria-current. Items are 2.5rem square so they clear the touch minimum.
   */
  .pf-pagination {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--pf-space-2);
  }
  .pf-pagination__item {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 2.5rem;
    min-height: 2.5rem;
    padding-inline: 0.75rem;
    background: var(--pf-surface);
    border: 1px solid var(--pf-border);
    border-radius: var(--pf-radius-sm);
    color: var(--pf-text-muted);
    font-size: var(--pf-text-sm);
    text-decoration: none;
    transition: border-color var(--pf-speed) var(--pf-ease), color var(--pf-speed) var(--pf-ease);
  }
  .pf-pagination__item:hover { border-color: var(--pf-border-strong); color: var(--pf-text); }
  .pf-pagination__item[aria-current] {
    background: var(--pf-accent);
    border-color: var(--pf-accent);
    color: var(--pf-base-950);
    font-weight: 600;
  }
  .pf-pagination__item[aria-disabled="true"] { opacity: 0.45; pointer-events: none; }
  .pf-pagination__gap { color: var(--pf-text-muted); padding-inline: 0.25rem; }
  
  /* ==========================================================================
     #PROGRESS AND METER
     ========================================================================== */
  
  /**
   * Progress
   *
   * <div class="pf-progress">
   *   <div class="pf-progress__bar" style="width: 62%" role="progressbar"
   *        aria-valuenow="62" aria-valuemin="0" aria-valuemax="100"></div>
   * </div>
   *
   * The width is the one place an inline style is unavoidable, because the
   * value is data. Everything else is here. Add --pf-progress-value if you
   * would rather set it as a custom property from your template.
   */
  .pf-progress {
    overflow: hidden;
    height: 0.6rem;
    background: var(--pf-surface-raised);
    border-radius: var(--pf-radius-pill);
  }
  .pf-progress__bar {
    height: 100%;
    width: var(--pf-progress-value, 0%);
    background: var(--pf-accent);
    border-radius: inherit;
    transition: width 400ms var(--pf-ease);
  }
  .pf-progress--lg { height: 1rem; }
  .pf-progress--secondary .pf-progress__bar { background: var(--pf-accent-2); }
  
  /* Segmented meter, for quotas and capacity. */
  .pf-meter {
    display: flex;
    gap: 3px;
    height: 0.6rem;
  }
  .pf-meter__seg {
    flex: 1;
    background: var(--pf-surface-raised);
    border-radius: 2px;
  }
  .pf-meter__seg--on { background: var(--pf-accent); }
  .pf-meter__seg--warn { background: var(--pf-accent-2); }
  
  /* ==========================================================================
     #SPINNER
     ========================================================================== */
  
  /**
   * Spinner
   *
   * <span class="pf-spinner" role="status" aria-label="Loading"></span>
   *
   * A rotating conic gradient rather than a border trick, so the tail fades
   * instead of stepping. Under prefers-reduced-motion it stops rotating and
   * becomes a static ring - Core's reduced-motion block handles that globally,
   * so a still ring must still read as "busy", which is why the aria-label is
   * part of the markup rather than optional.
   */
  .pf-spinner {
    display: inline-block;
    width: 1.25em;
    height: 1.25em;
    border-radius: 50%;
    background: conic-gradient(from 0turn, transparent 0deg, var(--pf-accent) 300deg);
    -webkit-mask: radial-gradient(farthest-side, transparent calc(100% - 3px), #000 0);
    mask: radial-gradient(farthest-side, transparent calc(100% - 3px), #000 0);
    animation: pf-spin 0.8s linear infinite;
    vertical-align: -0.2em;
  }
  .pf-spinner--lg { width: 2.5em; height: 2.5em; }
  @keyframes pf-spin { to { transform: rotate(1turn); } }
  
  /* ==========================================================================
     #LIST GROUP
     ========================================================================== */
  
  /**
   * List group
   *
   * Two valid shapes, and which one you need depends on the rows:
   *
   *   <ul class="pf-list">                    static rows
   *     <li class="pf-list__item">Label</li>
   *   </ul>
   *
   *   <div class="pf-list">                   rows that are links
   *     <div class="pf-list__item">Label</div>
   *     <a class="pf-list__item pf-list__item--link" href="/x">Clickable row</a>
   *   </div>
   *
   * An <a> is not valid as a direct child of <ul>, and wrapping each anchor in
   * an <li> breaks the adjacent-sibling selector that collapses the shared
   * borders. When any row is a link, use the <div> form.
   *
   * Rows share one border by collapsing them, so a list of ten does not read as
   * ten separate boxes. Use it for settings, file lists and result rows - the
   * places a table would be overkill.
   */
  .pf-list {
    display: flex;
    flex-direction: column;
    border: 1px solid var(--pf-border);
    border-radius: var(--pf-radius);
    overflow: hidden;
    margin: 0;
  }
  .pf-list__item {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--pf-space-4);
    background: var(--pf-surface);
    color: var(--pf-text);
    font-size: var(--pf-text-sm);
    padding: var(--pf-space-4) var(--pf-space-5);
    text-decoration: none;
    max-width: none;
  }
  .pf-list__item + .pf-list__item { border-top: 1px solid var(--pf-border); }
  .pf-list__item--link:hover { background: var(--pf-surface-raised); }
  .pf-list__item[aria-current] { box-shadow: inset 3px 0 0 var(--pf-accent); }
  .pf-list__title { font-weight: 600; }
  .pf-list__meta { color: var(--pf-text-muted); font-size: var(--pf-text-xs); }
  .pf-list--flush { border: 0; border-radius: 0; }
  .pf-list--flush .pf-list__item { background: none; padding-inline: 0; }
  
  /* ==========================================================================
     #AVATAR
     ========================================================================== */
  
  /**
   * Avatar
   *
   * <span class="pf-avatar" aria-hidden="true">JS</span>
   * <img class="pf-avatar" src="..." alt="Jo Silva">
   *
   * Initials are the default because an avatar without an image is the common
   * case in an internal tool. When it is decorative next to a name, mark it
   * aria-hidden so the name is not announced twice.
   */
  .pf-avatar {
    display: inline-grid;
    place-items: center;
    width: 2.25rem;
    height: 2.25rem;
    flex: none;
    background: var(--pf-surface-raised);
    border: 1px solid var(--pf-border);
    border-radius: 50%;
    color: var(--pf-text);
    font-size: var(--pf-text-xs);
    font-weight: 600;
    letter-spacing: 0.02em;
    object-fit: cover;
    overflow: hidden;
  }
  .pf-avatar--sm { width: 1.6rem; height: 1.6rem; font-size: 0.6rem; }
  .pf-avatar--lg { width: 3.25rem; height: 3.25rem; font-size: var(--pf-text-sm); }
  .pf-avatar--accent { background: var(--pf-accent); border-color: var(--pf-accent); color: var(--pf-base-950); }
  
  /* Overlapping stack. The ring is the page background, so members read as
     separate discs on any surface. */
  .pf-avatars { display: flex; }
  .pf-avatars > .pf-avatar + .pf-avatar { margin-inline-start: -0.6rem; }
  .pf-avatars > .pf-avatar { box-shadow: 0 0 0 2px var(--pf-bg); }
  
  /* ==========================================================================
     #SWITCH
     ========================================================================== */
  
  /**
   * Switch
   *
   * <label class="pf-switch">
   *   <input type="checkbox">
   *   <span class="pf-switch__track"></span>
   *   Weekly digest
   * </label>
   *
   * A real checkbox, visually hidden but focusable, with the track drawn from
   * its :checked state. Keyboard, form submission and autofill all behave
   * because the control was never replaced.
   */
  .pf-switch {
    display: inline-flex;
    align-items: center;
    gap: var(--pf-space-3);
    cursor: pointer;
    font-size: var(--pf-text-sm);
  }
  .pf-switch input {
    position: absolute;
    opacity: 0;
    width: 2.6rem;
    height: 1.5rem;
    margin: 0;
    cursor: pointer;
  }
  .pf-switch__track {
    position: relative;
    width: 2.6rem;
    height: 1.5rem;
    flex: none;
    background: var(--pf-surface-raised);
    border: 1px solid var(--pf-border);
    border-radius: var(--pf-radius-pill);
    transition: background-color var(--pf-speed) var(--pf-ease), border-color var(--pf-speed) var(--pf-ease);
  }
  .pf-switch__track::after {
    content: "";
    position: absolute;
    top: 50%;
    inset-inline-start: 3px;
    width: 1.05rem;
    height: 1.05rem;
    background: var(--pf-text-muted);
    border-radius: 50%;
    transform: translateY(-50%);
    transition: transform var(--pf-speed) var(--pf-ease), background-color var(--pf-speed) var(--pf-ease);
  }
  .pf-switch input:checked + .pf-switch__track {
    background: var(--pf-accent);
    border-color: var(--pf-accent);
  }
  .pf-switch input:checked + .pf-switch__track::after {
    background: var(--pf-base-950);
    transform: translate(1.05rem, -50%);
  }
  .pf-switch input:focus-visible + .pf-switch__track {
    outline: 2px solid var(--pf-focus);
    outline-offset: 2px;
  }
  .pf-switch input:disabled + .pf-switch__track { opacity: 0.45; }
  
  /* ==========================================================================
     #INPUT GROUP
     ========================================================================== */
  
  /**
   * Input group
   *
   * <div class="pf-input-group">
   *   <span class="pf-input-group__addon">https://</span>
   *   <input class="pf-input" type="text">
   *   <button class="pf-btn pf-btn--square" type="submit">Go</button>
   * </div>
   *
   * Needs Content for .pf-input. The focus ring is lifted to the whole group so
   * a focused field does not sit half-outlined against its addon.
   */
  .pf-input-group {
    display: flex;
    align-items: stretch;
    width: 100%;
  }
  .pf-input-group > * { border-radius: 0; }
  .pf-input-group > :first-child {
    border-start-start-radius: var(--pf-radius);
    border-end-start-radius: var(--pf-radius);
  }
  .pf-input-group > :last-child {
    border-start-end-radius: var(--pf-radius);
    border-end-end-radius: var(--pf-radius);
  }
  .pf-input-group > * + * { margin-inline-start: -1px; }
  .pf-input-group .pf-input { flex: 1; min-width: 0; }
  .pf-input-group .pf-input:focus { position: relative; z-index: 1; }
  .pf-input-group__addon {
    display: inline-flex;
    align-items: center;
    background: var(--pf-surface-raised);
    border: 1px solid var(--pf-border);
    color: var(--pf-text-muted);
    font-size: var(--pf-text-sm);
    padding-inline: var(--pf-space-4);
    white-space: nowrap;
  }
  
  /* ==========================================================================
     #TABS
     ========================================================================== */
  
  /**
   * Tabs, without JavaScript
   *
   * <div class="pf-tabs">
   *   <input class="pf-tabs__radio" type="radio" name="t" id="t1" checked>
   *   <label class="pf-tabs__label" for="t1">Overview</label>
   *   <input class="pf-tabs__radio" type="radio" name="t" id="t2">
   *   <label class="pf-tabs__label" for="t2">Details</label>
   *
   *   <div class="pf-tabs__panel"> ... first panel ... </div>
   *   <div class="pf-tabs__panel"> ... second panel ... </div>
   * </div>
   *
   * Radios in one group, labels styled as the strip, panels revealed by
   * :checked and :nth-of-type. Arrow keys move between radios natively, which
   * is the behaviour a scripted tablist has to reimplement.
   *
   * LIMIT: with no script there is no role="tab" wiring, so a screen reader
   * announces this as a radio group rather than a tablist. That is honest and
   * usable. If you need the full ARIA tab pattern you need the script.
   */
  .pf-tabs {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(0, max-content));
    border-bottom: 1px solid var(--pf-border);
    column-gap: var(--pf-space-2);
  }
  
  /**
   * Five tabs with real labels do not fit on a 320px screen. The strip scrolls
   * horizontally instead of wrapping, because a wrapped tab strip stops reading
   * as one control, and the panel keeps its full width underneath.
   */
  @media (max-width: 620px) {
    .pf-tabs {
      grid-auto-flow: column;
      grid-template-columns: none;
      justify-content: start;
      overflow-x: auto;
      overscroll-behavior-x: contain;
      scrollbar-width: thin;
    }
    .pf-tabs__panel { grid-column: 1 / -1; }
  }
  .pf-tabs__radio {
    position: absolute;
    opacity: 0;
    pointer-events: none;
  }
  .pf-tabs__label {
    grid-row: 1;
    padding: var(--pf-space-3) var(--pf-space-4);
    border-bottom: 2px solid transparent;
    color: var(--pf-text-muted);
    cursor: pointer;
    font-size: var(--pf-text-sm);
    font-weight: 500;
    white-space: nowrap;
  }
  .pf-tabs__label:hover { color: var(--pf-text); }
  .pf-tabs__panel {
    grid-row: 2;
    grid-column: 1 / -1;
    display: none;
    padding-top: var(--pf-space-5);
  }
  .pf-tabs__radio:checked + .pf-tabs__label {
    border-bottom-color: var(--pf-accent);
    color: var(--pf-text);
  }
  .pf-tabs__radio:focus-visible + .pf-tabs__label {
    outline: 2px solid var(--pf-focus);
    outline-offset: -2px;
  }
  .pf-tabs__radio:nth-of-type(1):checked ~ .pf-tabs__panel:nth-of-type(1),
  .pf-tabs__radio:nth-of-type(2):checked ~ .pf-tabs__panel:nth-of-type(2),
  .pf-tabs__radio:nth-of-type(3):checked ~ .pf-tabs__panel:nth-of-type(3),
  .pf-tabs__radio:nth-of-type(4):checked ~ .pf-tabs__panel:nth-of-type(4),
  .pf-tabs__radio:nth-of-type(5):checked ~ .pf-tabs__panel:nth-of-type(5) { display: block; }
  
  /* ==========================================================================
     #DISCLOSURE MENU
     ========================================================================== */
  
  /**
   * Disclosure menu
   *
   * <details class="pf-menu">
   *   <summary class="pf-menu__trigger">Actions</summary>
   *   <div class="pf-menu__list">
   *     <a class="pf-menu__item" href="/edit">Edit</a>
   *     <hr class="pf-menu__sep">
   *     <button class="pf-menu__item pf-menu__item--danger" type="button">Delete</button>
   *   </div>
   * </details>
   *
   * A dropdown built on <details>, so it opens on click and on Enter, closes on
   * Escape in current browsers, and needs no script.
   *
   * LIMIT: it does not close when you click elsewhere on the page. That genuinely
   * requires a listener. If that matters, wire one up - the CSS does not change.
   */
  .pf-menu { position: relative; display: inline-block; }
  .pf-menu__trigger {
    display: inline-flex;
    align-items: center;
    gap: var(--pf-space-2);
    background: var(--pf-surface);
    border: 1px solid var(--pf-border);
    border-radius: var(--pf-radius-pill);
    color: var(--pf-text);
    cursor: pointer;
    font-size: var(--pf-text-sm);
    font-weight: 500;
    list-style: none;
    padding: 0.7em 1.2em;
  }
  .pf-menu__trigger::-webkit-details-marker { display: none; }
  .pf-menu__trigger::after {
    content: "";
    width: 0.55em;
    height: 0.55em;
    background: var(--pf-accent);
    clip-path: polygon(50% 100%, 0 0, 100% 0);
  }
  .pf-menu[open] .pf-menu__trigger { border-color: var(--pf-border-strong); }
  .pf-menu__list {
    position: absolute;
    z-index: 40;
    top: calc(100% + 0.4rem);
    inset-inline-start: 0;
    min-width: 12rem;
    /* Capped against the viewport: a 12rem minimum anchored near the right
       edge of a 320px screen would otherwise sit half off it. */
    max-width: min(18rem, calc(100vw - 2rem));
    display: grid;
    background: var(--pf-bg-deep);
    border: 1px solid var(--pf-border);
    border-radius: var(--pf-radius);
    box-shadow: var(--pf-lift);
    padding: var(--pf-space-2);
  }
  .pf-menu--end .pf-menu__list { inset-inline-start: auto; inset-inline-end: 0; }
  .pf-menu__item {
    display: flex;
    align-items: center;
    gap: var(--pf-space-3);
    background: none;
    border: 0;
    border-radius: var(--pf-radius-sm);
    color: var(--pf-text);
    cursor: pointer;
    font-size: var(--pf-text-sm);
    padding: var(--pf-space-2) var(--pf-space-3);
    text-align: start;
    text-decoration: none;
    width: 100%;
  }
  .pf-menu__item:hover { background: var(--pf-surface-raised); color: var(--pf-text); }
  .pf-menu__item--danger { color: #e08f8f; }
  .pf-menu__sep { border: 0; border-top: 1px solid var(--pf-border); margin: var(--pf-space-2) 0; }
  
  /* ==========================================================================
     #DIALOG
     ========================================================================== */
  
  /**
   * Dialog
   *
   * Native, when you have a script to call showModal():
   *   <dialog class="pf-dialog"> ... </dialog>
   *
   * Or CSS-only, addressed by fragment:
   *   <a class="pf-btn" href="#confirm">Delete</a>
   *   <div class="pf-dialog-target" id="confirm">
   *     <div class="pf-dialog__panel">
   *       <a class="pf-dialog__close" href="#" aria-label="Close">&times;</a>
   *       ...
   *     </div>
   *   </div>
   *
   * The native version gets focus trapping and Escape for free and should be
   * preferred whenever a script exists. The :target version is a genuine
   * fallback, not a replacement: it does not trap focus, so use it for simple
   * confirmations rather than complex forms.
   */
  .pf-dialog {
    max-width: min(32rem, calc(100vw - 2rem));
    background: var(--pf-bg-deep);
    border: 1px solid var(--pf-border-strong);
    border-radius: var(--pf-radius-lg);
    color: var(--pf-text);
    padding: var(--pf-space-6);
  }
  .pf-dialog::backdrop { background: rgba(0, 4, 18, 0.72); }
  
  .pf-dialog-target {
    position: fixed;
    inset: 0;
    z-index: 60;
    display: none;
    place-items: center;
    padding: var(--pf-space-4);
    background: rgba(0, 4, 18, 0.72);
  }
  .pf-dialog-target:target { display: grid; }
  .pf-dialog__panel {
    position: relative;
    width: min(32rem, 100%);
    background: var(--pf-bg-deep);
    border: 1px solid var(--pf-border-strong);
    border-radius: var(--pf-radius-lg);
    padding: var(--pf-space-6);
  }
  .pf-dialog__close {
    position: absolute;
    top: var(--pf-space-3);
    inset-inline-end: var(--pf-space-4);
    color: var(--pf-text-muted);
    font-size: 1.4rem;
    line-height: 1;
    text-decoration: none;
  }
  .pf-dialog__close:hover { color: var(--pf-text); }
  .pf-dialog__title { font-family: var(--pf-font-display); font-size: var(--pf-text-xl); }
  .pf-dialog__foot {
    display: flex;
    flex-wrap: wrap;
    justify-content: flex-end;
    gap: var(--pf-space-3);
    margin-top: var(--pf-space-5);
  }
  
  /* ==========================================================================
     #TOOLTIP
     ========================================================================== */
  
  /**
   * Tooltip
   *
   * <button class="pf-btn pf-tooltip" data-pf-tip="Copies to clipboard">Copy</button>
   *
   * Shown on hover AND on keyboard focus - hover-only tooltips are invisible to
   * anyone tabbing through. The text comes from a data attribute so it is not
   * announced twice; when the tip carries information the control does not, put
   * it in aria-describedby content instead of here.
   */
  .pf-tooltip { position: relative; }
  .pf-tooltip::after {
    content: attr(data-pf-tip);
    position: absolute;
    bottom: calc(100% + 0.5rem);
    inset-inline-start: 50%;
    z-index: 50;
    width: max-content;
    max-width: 16rem;
    background: var(--pf-bg-deep);
    border: 1px solid var(--pf-border);
    border-radius: var(--pf-radius-sm);
    color: var(--pf-text);
    font-size: var(--pf-text-xs);
    font-weight: 400;
    line-height: 1.4;
    padding: 0.4rem 0.6rem;
    opacity: 0;
    pointer-events: none;
    transform: translate(-50%, 0.25rem);
    transition: opacity var(--pf-speed) var(--pf-ease), transform var(--pf-speed) var(--pf-ease);
  }
  .pf-tooltip:hover::after,
  .pf-tooltip:focus-visible::after { opacity: 1; transform: translate(-50%, 0); }
  .pf-tooltip--end::after { inset-inline-start: auto; inset-inline-end: 0; transform: translate(0, 0.25rem); }
  .pf-tooltip--end:hover::after,
  .pf-tooltip--end:focus-visible::after { transform: translate(0, 0); }
  
  /* ==========================================================================
     #RATIO BOX
     ========================================================================== */
  
  /**
   * Ratio
   *
   * <div class="pf-ratio pf-ratio--16x9">
   *   <iframe src="..." title="..."></iframe>
   * </div>
   *
   * Holds space for an embed before it loads, which is most of the layout shift
   * on a page with video.
   */
  .pf-ratio { position: relative; width: 100%; aspect-ratio: var(--pf-ratio, 16 / 9); }
  .pf-ratio > * { position: absolute; inset: 0; width: 100%; height: 100%; border: 0; }
  .pf-ratio--1x1 { --pf-ratio: 1 / 1; }
  .pf-ratio--4x3 { --pf-ratio: 4 / 3; }
  .pf-ratio--16x9 { --pf-ratio: 16 / 9; }
  .pf-ratio--21x9 { --pf-ratio: 21 / 9; }
  
  /* ==========================================================================
     #SKELETON
     ========================================================================== */
  
  /**
   * Skeleton
   *
   * <div class="pf-skeleton pf-skeleton--title"></div>
   * <div class="pf-skeleton pf-skeleton--text"></div>
   *
   * Placeholder blocks at the shape of the content that is coming. Mark the
   * region aria-busy="true" so it is not read as empty content.
   */
  .pf-skeleton {
    background: linear-gradient(90deg, var(--pf-surface) 25%, var(--pf-surface-raised) 37%, var(--pf-surface) 63%);
    background-size: 400% 100%;
    border-radius: var(--pf-radius-sm);
    height: 0.9rem;
    animation: pf-skeleton 1.4s ease infinite;
  }
  .pf-skeleton--title { height: 1.6rem; width: 60%; }
  .pf-skeleton--text { width: 100%; margin-top: var(--pf-space-3); }
  .pf-skeleton--text:nth-of-type(3n) { width: 82%; }
  .pf-skeleton--block { height: 8rem; border-radius: var(--pf-radius); }
  .pf-skeleton--circle { height: 2.25rem; width: 2.25rem; border-radius: 50%; }
  @keyframes pf-skeleton { from { background-position: 100% 50%; } to { background-position: 0 50%; } }
  
  /* ==========================================================================
     #EMPTY STATE
     ========================================================================== */
  
  /**
   * Empty state
   *
   * <div class="pf-empty">
   *   <span class="pf-empty__mark"></span>
   *   <h3 class="pf-empty__title">No checks yet</h3>
   *   <p class="pf-empty__body">Point us at a URL and we will start watching it.</p>
   *   <a class="pf-btn" href="/new">Add a check</a>
   * </div>
   *
   * Say what is missing and give the action that fixes it. An empty table with
   * no explanation is the most common unfinished screen in an internal tool.
   */
  .pf-empty {
    display: grid;
    justify-items: center;
    gap: var(--pf-space-3);
    border: 1px dashed var(--pf-border);
    border-radius: var(--pf-radius-lg);
    padding: var(--pf-space-8) var(--pf-space-5);
    text-align: center;
  }
  .pf-empty__mark {
    width: 2.5rem;
    height: 2.5rem;
    background: var(--pf-accent);
    opacity: 0.5;
    clip-path: polygon(50% 0, 100% 100%, 0 100%);
  }
  .pf-empty__title { font-family: var(--pf-font-display); font-size: var(--pf-text-xl); }
  .pf-empty__body { color: var(--pf-text-muted); max-width: 44ch; }
  
  /* ==========================================================================
     #DIVIDER
     ========================================================================== */
  
  /**
   * Divider with an optional label:
   *   <div class="pf-divider"><span>or</span></div>
   */
  .pf-divider {
    display: flex;
    align-items: center;
    gap: var(--pf-space-4);
    color: var(--pf-text-muted);
    font-size: var(--pf-text-xs);
  }
  .pf-divider::before,
  .pf-divider::after {
    content: "";
    flex: 1;
    height: 1px;
    background: var(--pf-border);
  }
  
  /* ==========================================================================
     #DRAWER
     ========================================================================== */
  
  /**
   * Drawer (offcanvas)
   *
   * <a class="pf-btn" href="#filters">Filters</a>
   *
   * <div class="pf-drawer" id="filters" role="dialog" aria-modal="true"
   *      aria-labelledby="filters-title">
   *   <a class="pf-drawer__scrim" href="#" aria-label="Close"></a>
   *   <div class="pf-drawer__panel">
   *     <div class="pf-drawer__head">
   *       <h2 class="pf-drawer__title" id="filters-title">Filters</h2>
   *       <a class="pf-btn pf-btn--ghost pf-btn--icon pf-btn--sm" href="#"
   *          aria-label="Close">&times;</a>
   *     </div>
   *     <div class="pf-drawer__body"> ... </div>
   *   </div>
   * </div>
   *
   * Variants: --end (slides from the right)  --bottom (a phone sheet)
   *
   * Opens on :target with no script. Add data-pf-drawer to have the optional
   * script close it on Escape and return focus to the trigger.
   *
   * The panel is a flex column with a scrolling body, so a long filter list
   * scrolls inside the drawer instead of the page behind it. Both the panel and
   * the body carry safe-area padding: a bottom sheet on a gesture-navigation
   * phone otherwise ends underneath the home indicator.
   */
  .pf-drawer {
    position: fixed;
    inset: 0;
    z-index: 70;
    display: none;
  }
  .pf-drawer:target { display: block; }
  
  .pf-drawer__scrim {
    position: absolute;
    inset: 0;
    background: rgba(0, 4, 18, 0.6);
    display: block;
  }
  
  .pf-drawer__panel {
    position: absolute;
    inset-block: 0;
    inset-inline-start: 0;
    display: flex;
    flex-direction: column;
    width: min(22rem, 88vw);
    background: var(--pf-bg-deep);
    border-inline-end: 1px solid var(--pf-border);
    box-shadow: var(--pf-lift);
    padding-bottom: env(safe-area-inset-bottom);
  }
  .pf-drawer--end .pf-drawer__panel {
    inset-inline: auto 0;
    border-inline: 1px solid var(--pf-border) none;
  }
  .pf-drawer--bottom .pf-drawer__panel {
    inset: auto 0 0;
    width: auto;
    max-height: 82dvh;
    border: 1px solid var(--pf-border);
    border-radius: var(--pf-radius-lg) var(--pf-radius-lg) 0 0;
  }
  
  .pf-drawer__head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--pf-space-4);
    border-bottom: 1px solid var(--pf-border);
    padding: var(--pf-space-4) var(--pf-space-5);
  }
  .pf-drawer__title { font-family: var(--pf-font-display); font-size: var(--pf-text-lg); }
  .pf-drawer__body {
    flex: 1;
    overflow-y: auto;
    overscroll-behavior: contain;
    padding: var(--pf-space-5);
  }
  .pf-drawer__foot {
    border-top: 1px solid var(--pf-border);
    display: flex;
    gap: var(--pf-space-3);
    padding: var(--pf-space-4) var(--pf-space-5);
    padding-bottom: max(var(--pf-space-4), env(safe-area-inset-bottom));
  }
  .pf-drawer__foot > .pf-btn { flex: 1; }
  
  /* A grab handle reads as "this can be dismissed" on a bottom sheet. */
  .pf-drawer--bottom .pf-drawer__head::before {
    content: "";
    position: absolute;
    top: 0.5rem;
    inset-inline-start: 50%;
    width: 2.5rem;
    height: 0.25rem;
    border-radius: var(--pf-radius-pill);
    background: var(--pf-border-strong);
    transform: translateX(-50%);
  }
  .pf-drawer--bottom .pf-drawer__head { position: relative; padding-top: var(--pf-space-6); }
  
  /* ==========================================================================
     #BOTTOM BAR
     ========================================================================== */
  
  /**
   * Bottom bar
   *
   * <nav class="pf-bottombar" aria-label="Primary">
   *   <a class="pf-bottombar__item" href="/" aria-current="page">
   *     <span class="pf-bottombar__mark" aria-hidden="true"></span> Home
   *   </a>
   * </nav>
   *
   * A phone-only navigation bar pinned to the bottom, where a thumb actually
   * reaches. Hidden from 860px up, where the top navigation takes over.
   *
   * Two details that are not optional: the safe-area padding, or the last row
   * of items sits under the home indicator, and the matching padding on <body>
   * (.pf-has-bottombar), or the bar covers the end of the page with no way to
   * scroll past it.
   */
  .pf-bottombar {
    position: fixed;
    inset: auto 0 0;
    z-index: 45;
    display: flex;
    justify-content: space-around;
    gap: var(--pf-space-2);
    background: color-mix(in srgb, var(--pf-bg-deep) 92%, transparent);
    -webkit-backdrop-filter: blur(12px);
    backdrop-filter: blur(12px);
    border-top: 1px solid var(--pf-border);
    padding: var(--pf-space-2) var(--pf-space-3);
    padding-bottom: max(var(--pf-space-2), env(safe-area-inset-bottom));
  }
  .pf-bottombar__item {
    display: grid;
    justify-items: center;
    gap: 0.2rem;
    flex: 1;
    min-height: 44px;
    align-content: center;
    border-radius: var(--pf-radius-sm);
    color: var(--pf-text-muted);
    font-size: var(--pf-text-xs);
    text-decoration: none;
  }
  .pf-bottombar__item[aria-current] { color: var(--pf-accent); }
  .pf-bottombar__mark {
    width: 1.1rem;
    height: 1.1rem;
    background: currentColor;
    clip-path: polygon(50% 0, 100% 100%, 0 100%);
  }
  .pf-has-bottombar { padding-bottom: calc(4.5rem + env(safe-area-inset-bottom)); }
  
  @media (min-width: 860px) {
    .pf-bottombar { display: none; }
    .pf-has-bottombar { padding-bottom: 0; }
  }
  
  /* ==========================================================================
     #TOAST
     ========================================================================== */
  
  /**
   * Toast
   *
   * The region is markup you add once; the messages come from the script:
   *
   *   <div class="pf-toasts" id="pf-toasts" role="status" aria-live="polite"></div>
   *   PolyFish.toast("Check created");
   *
   * This is the one component that genuinely requires JavaScript, and it is
   * marked as such: there is no CSS-only fallback, because a toast with no
   * script is an empty box.
   *
   * role="status" with aria-live="polite" queues the message behind whatever
   * the screen reader is currently saying. An assertive live region interrupts
   * mid-sentence, which for a confirmation message is rude rather than urgent.
   *
   * Positioned above the bottom bar and clear of the safe area.
   */
  .pf-toasts {
    position: fixed;
    inset: auto 0 0;
    z-index: 80;
    display: grid;
    justify-items: center;
    gap: var(--pf-space-2);
    padding: var(--pf-space-4);
    padding-bottom: max(var(--pf-space-4), env(safe-area-inset-bottom));
    pointer-events: none;
  }
  .pf-has-bottombar .pf-toasts { padding-bottom: calc(4.5rem + env(safe-area-inset-bottom)); }
  
  .pf-toast {
    display: flex;
    align-items: center;
    gap: var(--pf-space-3);
    width: min(26rem, 100%);
    background: var(--pf-bg-deep);
    border: 1px solid var(--pf-border-strong);
    border-radius: var(--pf-radius);
    box-shadow: var(--pf-lift);
    color: var(--pf-text);
    font-size: var(--pf-text-sm);
    padding: var(--pf-space-3) var(--pf-space-4);
    pointer-events: auto;
    animation: pf-toast-in 220ms var(--pf-ease) both;
  }
  .pf-toast--accent { border-color: var(--pf-accent); }
  .pf-toast--danger { border-color: #e08f8f; }
  .pf-toast__close { margin-inline-start: auto; }
  
  @keyframes pf-toast-in {
    from { opacity: 0; transform: translateY(0.75rem); }
    to { opacity: 1; transform: none; }
  }
  
  @media (min-width: 620px) {
    .pf-toasts { inset: auto 0 0 auto; justify-items: end; }
  }
  
  /* ==========================================================================
     #TOOLBAR
     ========================================================================== */
  
  /**
   * Toolbar
   *
   * <div class="pf-toolbar">
   *   <div class="pf-toolbar__group"> ... </div>
   *   <div class="pf-toolbar__group pf-toolbar__group--end"> ... </div>
   * </div>
   *
   * The row of controls above a table or list. Wraps rather than scrolls, so a
   * narrow screen stacks the groups instead of hiding half of them.
   */
  .pf-toolbar {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: var(--pf-space-4);
    padding-block: var(--pf-space-3);
  }
  .pf-toolbar__group { display: flex; flex-wrap: wrap; align-items: center; gap: var(--pf-space-3); }
  .pf-toolbar__group--end { margin-inline-start: auto; }
  .pf-toolbar--bordered {
    border: 1px solid var(--pf-border);
    border-radius: var(--pf-radius);
    padding: var(--pf-space-3) var(--pf-space-4);
  }
}

/* ===== PolyFishCSS-Footers.css ===== */
/*! PolyFishCSS-Footers.css | v1.0.0-rc.2-rc.1-rc.1-rc.1-rc.1-rc.1 | polyfish.org | MIT
 *
 * Three footers: a column footer for marketing pages, a one-line slim
 * variant for docs and app shells, and a full-bleed accent variant.
 *
 * Depends on: PolyFishCSS-Core.css. The optional signup form also needs Content
 *             (.pf-input, .pf-label, .pf-help).
 * Load order: Core -> Headers -> Content -> Footers -> Utilities.
 *
 * CONTENTS
 *   1. Column footer
 *   2. Brand block and signup
 *   3. Link columns
 *   4. Social row
 *   5. Legal bar and back-to-top
 *   6. Slim variant
 *   7. Accent variant
 *
 * CONVENTIONS
 *   .pf-block / .pf-block__element / .pf-block--modifier.
 *   Components read role tokens, never palette values. See docs/tokens.
 *
 * MARKUP
 *   <footer class="pf-footer">
 *     <div class="pf-container">
 *       <div class="pf-footer__top">
 *         <div class="pf-footer__brand"> ... </div>
 *         <div class="pf-footer__col">
 *           <h2 class="pf-footer__heading">Group</h2>
 *           <ul class="pf-footer__links"> ... </ul>
 *         </div>
 *       </div>
 *       <div class="pf-footer__bottom"> ... </div>
 *     </div>
 *   </footer>
 * 
 *   The column grid is one auto-fit repeat with a wider first track, so columns
 *   collapse in a single step instead of the four-breakpoint staircase most
 *   footers end up with. Below 760px the brand block spans the full row.
 */

@layer polyfish.core, polyfish.grid, polyfish.headers, polyfish.content, polyfish.forms, polyfish.components, polyfish.footers, polyfish.space, polyfish.effects, polyfish.utilities, polyfish.fonts, polyfish.compat;

/* ==========================================================================
   CASCADE LAYER
   ==========================================================================
   Everything below sits in `polyfish.footers`. The layer order is declared in
   every module, so it holds no matter which order you link the files in.

   Why this matters to you: unlayered CSS beats layered CSS regardless of
   specificity. Your own stylesheet overrides any framework rule with a plain
   class selector — no `!important`, no specificity arms race, no worrying
   about whether Utilities loaded last.

     <link rel="stylesheet" href="PolyFishCSS-Core.min.css">
     <link rel="stylesheet" href="my-app.css">   <!-- wins, always -->

   If you want your CSS layered too, name a layer after the framework's:

     @layer polyfish, app;
     @layer app { .card { background: rebeccapurple; } }
   ========================================================================== */

@layer polyfish.footers {
  .pf-footer {
    background: var(--pf-base-900);
    border-top: 1px solid var(--pf-border);
    color: var(--pf-text-muted);
    font-size: var(--pf-text-base);
    padding-block: clamp(4rem, 9vw, 7rem) var(--pf-space-6);
    /* Clear of the home indicator on a gesture-navigation phone. */
    padding-bottom: max(var(--pf-space-6), env(safe-area-inset-bottom));
  }
  
  .pf-footer__top {
    display: grid;
    gap: var(--pf-gap-lg);
    grid-template-columns: minmax(240px, 1.4fr) repeat(auto-fit, minmax(150px, 1fr));
  }
  @media (max-width: 760px) {
    .pf-footer__top { grid-template-columns: repeat(auto-fit, minmax(min(150px, 100%), 1fr)); }
    .pf-footer__brand { grid-column: 1 / -1; }
  }
  
  .pf-footer__brand { display: grid; gap: var(--pf-space-3); align-content: start; }
  .pf-footer__brand a.pf-footer__logo {
    display: inline-flex;
    align-items: center;
    gap: 0.6rem;
    color: var(--pf-base-50);
    font-family: var(--pf-font-display);
    font-size: 1.15rem;
    font-weight: 800;
    letter-spacing: -0.02em;
    text-decoration: none;
  }
  .pf-footer__brand img,
  .pf-footer__brand svg { width: 2rem; height: 2rem; }
  .pf-footer__brand p { max-width: 34ch; line-height: 1.6; }
  
  .pf-footer__col { display: grid; gap: var(--pf-space-3); align-content: start; }
  .pf-footer__heading {
    color: var(--pf-base-50);
    font-family: var(--pf-font-body);
    font-size: var(--pf-text-sm);
    font-weight: 600;
  }
  .pf-footer__links { display: grid; gap: var(--pf-space-2); margin: 0; }
  .pf-footer__links a { color: var(--pf-text-muted); text-decoration: none; }
  .pf-footer__links a:hover { color: var(--pf-accent); }
  .pf-footer__links a[aria-current] { color: var(--pf-base-50); }
  
  .pf-footer__signup { display: grid; gap: var(--pf-space-2); max-width: 26rem; }
  
  .pf-social { display: flex; flex-wrap: wrap; gap: var(--pf-space-2); margin: 0; }
  .pf-social a {
    display: grid;
    place-items: center;
    width: 2.25rem;
    height: 2.25rem;
    border: 1px solid var(--pf-border);
    border-radius: var(--pf-radius-sm);
    color: var(--pf-text-muted);
    text-decoration: none;
    transition: border-color var(--pf-speed) var(--pf-ease), color var(--pf-speed) var(--pf-ease);
  }
  .pf-social a:hover { border-color: var(--pf-accent); color: var(--pf-accent); }
  .pf-social svg { width: 1.05rem; height: 1.05rem; fill: currentColor; }
  
  .pf-footer__bottom {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: var(--pf-space-4);
    border-top: 1px solid var(--pf-border);
    margin-top: var(--pf-space-7);
    padding-top: var(--pf-space-5);
    font-size: var(--pf-text-sm);
  }
  .pf-footer__legal { display: flex; flex-wrap: wrap; gap: var(--pf-space-4); margin: 0; }
  .pf-footer__legal a { color: var(--pf-text-muted); text-decoration: none; }
  .pf-footer__legal a:hover { color: var(--pf-accent); }
  
  .pf-totop {
    display: inline-flex;
    align-items: center;
    gap: var(--pf-space-2);
    color: var(--pf-text-muted);
    text-decoration: none;
  }
  .pf-totop::after {
    content: "";
    width: 0.65rem;
    height: 0.65rem;
    background: var(--pf-accent);
    clip-path: polygon(50% 0, 100% 100%, 0 100%);
  }
  .pf-totop:hover { color: var(--pf-accent); }
  
  /**
   * Slim
   *
   * <footer class="pf-footer pf-footer--slim">
   *   <div class="pf-container pf-footer__bottom"> ... </div>
   * </footer>
   *
   * Drop the __top block entirely and use only __bottom. For documentation and
   * application shells, where a five-column footer is more navigation than the
   * page itself.
   */
  .pf-footer--slim { padding-block: var(--pf-space-5); }
  .pf-footer--slim .pf-footer__bottom { border-top: 0; margin-top: 0; padding-top: 0; }
  
  /**
   * Accent
   *
   * <footer class="pf-footer pf-footer--accent"> ... </footer>
   *
   * Recolours every child - headings, links, social row, legal bar, the
   * back-to-top marker - because a footer that flips its background and forgets
   * one of those is worse than not flipping at all. Combine with --slim.
   */
  .pf-footer--accent {
    background: var(--pf-hue-1);
    border-top-color: transparent;
    color: rgba(0, 16, 58, 0.72);
  }
  .pf-footer--accent .pf-footer__brand a.pf-footer__logo,
  .pf-footer--accent .pf-footer__heading { color: var(--pf-base-950); }
  .pf-footer--accent .pf-footer__links a,
  .pf-footer--accent .pf-footer__legal a,
  .pf-footer--accent .pf-totop { color: rgba(0, 16, 58, 0.72); }
  .pf-footer--accent .pf-footer__links a:hover,
  .pf-footer--accent .pf-footer__legal a:hover,
  .pf-footer--accent .pf-totop:hover { color: var(--pf-base-950); }
  .pf-footer--accent .pf-footer__bottom { border-top-color: rgba(0, 16, 58, 0.2); }
  .pf-footer--accent .pf-social a { border-color: rgba(0, 16, 58, 0.25); color: rgba(0, 16, 58, 0.72); }
  .pf-footer--accent .pf-social a:hover { border-color: var(--pf-base-950); color: var(--pf-base-950); }
  .pf-footer--accent .pf-totop::after { background: var(--pf-base-800); }
}

/* ===== PolyFishCSS-Space.css ===== */
/*! PolyFishCSS-Space.css | v1.0.0-rc.2-rc.1-rc.1-rc.1-rc.1-rc.1 | polyfish.org | MIT
 *
 * The full spacing and sizing utility surface: padding and margin on every
 * side, gaps, grid track shorthands, flex sizing and placement.
 *
 * Depends on: PolyFishCSS-Core.css (the space scale and gap tokens).
 * Load order: after Core, with the other utility files at the end.
 *
 * CONTENTS
 *   1. Padding
 *   2. Margin
 *   3. Gap
 *   4. Grid tracks and placement
 *   5. Flex sizing
 *   6. Responsive spacing
 *
 * NAMING
 *   .pf-p-4      padding on all sides
 *   .pf-px-4     padding inline (left and right, and RTL-correct)
 *   .pf-py-4     padding block (top and bottom)
 *   .pf-pt-4     padding top          -pr- right  -pb- bottom  -pl- left
 *   .pf-m-*      the same set for margin, plus -auto
 *   .pf-md-p-4   from 768px up
 *
 *   The suffix is a step on the space scale, not a pixel value. Retuning
 *   --pf-space-* retunes every utility with it, which is the difference
 *   between a scale and a pile of numbers.
 *
 * ON SIZE
 *   This file is roughly 700 declarations. That is the cost of a utility
 *   surface without a compiler to purge it - the trade is no build step, and
 *   it gzips to a few kilobytes because the strings repeat. If you would
 *   rather not carry it, do not load it: nothing else depends on this module.
 */

@layer polyfish.core, polyfish.grid, polyfish.headers, polyfish.content, polyfish.forms, polyfish.components, polyfish.footers, polyfish.space, polyfish.effects, polyfish.utilities, polyfish.fonts, polyfish.compat;

/* ==========================================================================
   CASCADE LAYER
   ==========================================================================
   Everything below sits in `polyfish.space`. The layer order is declared in
   every module, so it holds no matter which order you link the files in.

   Why this matters to you: unlayered CSS beats layered CSS regardless of
   specificity. Your own stylesheet overrides any framework rule with a plain
   class selector — no `!important`, no specificity arms race, no worrying
   about whether Utilities loaded last.

     <link rel="stylesheet" href="PolyFishCSS-Core.min.css">
     <link rel="stylesheet" href="my-app.css">   <!-- wins, always -->

   If you want your CSS layered too, name a layer after the framework's:

     @layer polyfish, app;
     @layer app { .card { background: rebeccapurple; } }
   ========================================================================== */

@layer polyfish.space {
  /* ==========================================================================
     #PADDING
     ========================================================================== */
  .pf-p-0 { padding: 0; }
  .pf-p-1 { padding: var(--pf-space-1); }
  .pf-p-2 { padding: var(--pf-space-2); }
  .pf-p-3 { padding: var(--pf-space-3); }
  .pf-p-4 { padding: var(--pf-space-4); }
  .pf-p-5 { padding: var(--pf-space-5); }
  .pf-p-6 { padding: var(--pf-space-6); }
  .pf-p-7 { padding: var(--pf-space-7); }
  .pf-p-8 { padding: var(--pf-space-8); }
  .pf-p-9 { padding: var(--pf-space-9); }
  .pf-p-px { padding: 1px; }
  
  .pf-px-0 { padding-inline: 0; }
  .pf-px-1 { padding-inline: var(--pf-space-1); }
  .pf-px-2 { padding-inline: var(--pf-space-2); }
  .pf-px-3 { padding-inline: var(--pf-space-3); }
  .pf-px-4 { padding-inline: var(--pf-space-4); }
  .pf-px-5 { padding-inline: var(--pf-space-5); }
  .pf-px-6 { padding-inline: var(--pf-space-6); }
  .pf-px-7 { padding-inline: var(--pf-space-7); }
  .pf-px-8 { padding-inline: var(--pf-space-8); }
  .pf-px-9 { padding-inline: var(--pf-space-9); }
  .pf-px-px { padding-inline: 1px; }
  
  .pf-py-0 { padding-block: 0; }
  .pf-py-1 { padding-block: var(--pf-space-1); }
  .pf-py-2 { padding-block: var(--pf-space-2); }
  .pf-py-3 { padding-block: var(--pf-space-3); }
  .pf-py-4 { padding-block: var(--pf-space-4); }
  .pf-py-5 { padding-block: var(--pf-space-5); }
  .pf-py-6 { padding-block: var(--pf-space-6); }
  .pf-py-7 { padding-block: var(--pf-space-7); }
  .pf-py-8 { padding-block: var(--pf-space-8); }
  .pf-py-9 { padding-block: var(--pf-space-9); }
  .pf-py-px { padding-block: 1px; }
  
  .pf-pt-0 { padding-top: 0; }
  .pf-pt-1 { padding-top: var(--pf-space-1); }
  .pf-pt-2 { padding-top: var(--pf-space-2); }
  .pf-pt-3 { padding-top: var(--pf-space-3); }
  .pf-pt-4 { padding-top: var(--pf-space-4); }
  .pf-pt-5 { padding-top: var(--pf-space-5); }
  .pf-pt-6 { padding-top: var(--pf-space-6); }
  .pf-pt-7 { padding-top: var(--pf-space-7); }
  .pf-pt-8 { padding-top: var(--pf-space-8); }
  .pf-pt-9 { padding-top: var(--pf-space-9); }
  .pf-pt-px { padding-top: 1px; }
  
  .pf-pe-0 { padding-inline-end: 0; }
  .pf-pe-1 { padding-inline-end: var(--pf-space-1); }
  .pf-pe-2 { padding-inline-end: var(--pf-space-2); }
  .pf-pe-3 { padding-inline-end: var(--pf-space-3); }
  .pf-pe-4 { padding-inline-end: var(--pf-space-4); }
  .pf-pe-5 { padding-inline-end: var(--pf-space-5); }
  .pf-pe-6 { padding-inline-end: var(--pf-space-6); }
  .pf-pe-7 { padding-inline-end: var(--pf-space-7); }
  .pf-pe-8 { padding-inline-end: var(--pf-space-8); }
  .pf-pe-9 { padding-inline-end: var(--pf-space-9); }
  .pf-pe-px { padding-inline-end: 1px; }
  
  .pf-pb-0 { padding-bottom: 0; }
  .pf-pb-1 { padding-bottom: var(--pf-space-1); }
  .pf-pb-2 { padding-bottom: var(--pf-space-2); }
  .pf-pb-3 { padding-bottom: var(--pf-space-3); }
  .pf-pb-4 { padding-bottom: var(--pf-space-4); }
  .pf-pb-5 { padding-bottom: var(--pf-space-5); }
  .pf-pb-6 { padding-bottom: var(--pf-space-6); }
  .pf-pb-7 { padding-bottom: var(--pf-space-7); }
  .pf-pb-8 { padding-bottom: var(--pf-space-8); }
  .pf-pb-9 { padding-bottom: var(--pf-space-9); }
  .pf-pb-px { padding-bottom: 1px; }
  
  .pf-ps-0 { padding-inline-start: 0; }
  .pf-ps-1 { padding-inline-start: var(--pf-space-1); }
  .pf-ps-2 { padding-inline-start: var(--pf-space-2); }
  .pf-ps-3 { padding-inline-start: var(--pf-space-3); }
  .pf-ps-4 { padding-inline-start: var(--pf-space-4); }
  .pf-ps-5 { padding-inline-start: var(--pf-space-5); }
  .pf-ps-6 { padding-inline-start: var(--pf-space-6); }
  .pf-ps-7 { padding-inline-start: var(--pf-space-7); }
  .pf-ps-8 { padding-inline-start: var(--pf-space-8); }
  .pf-ps-9 { padding-inline-start: var(--pf-space-9); }
  .pf-ps-px { padding-inline-start: 1px; }
  
  
  /* ==========================================================================
     #MARGIN
     ==========================================================================
     Negative steps are deliberately absent. A negative margin is almost always
     a symptom of a layout fighting its container, and a utility for it makes
     that easy to reach for twice. Use gap, or fix the container.
     ========================================================================== */
  
  .pf-m-0 { margin: 0; }
  .pf-m-1 { margin: var(--pf-space-1); }
  .pf-m-2 { margin: var(--pf-space-2); }
  .pf-m-3 { margin: var(--pf-space-3); }
  .pf-m-4 { margin: var(--pf-space-4); }
  .pf-m-5 { margin: var(--pf-space-5); }
  .pf-m-6 { margin: var(--pf-space-6); }
  .pf-m-7 { margin: var(--pf-space-7); }
  .pf-m-8 { margin: var(--pf-space-8); }
  .pf-m-9 { margin: var(--pf-space-9); }
  .pf-m-auto { margin: auto; }
  .pf-m-px { margin: 1px; }
  
  .pf-mx-0 { margin-inline: 0; }
  .pf-mx-1 { margin-inline: var(--pf-space-1); }
  .pf-mx-2 { margin-inline: var(--pf-space-2); }
  .pf-mx-3 { margin-inline: var(--pf-space-3); }
  .pf-mx-4 { margin-inline: var(--pf-space-4); }
  .pf-mx-5 { margin-inline: var(--pf-space-5); }
  .pf-mx-6 { margin-inline: var(--pf-space-6); }
  .pf-mx-7 { margin-inline: var(--pf-space-7); }
  .pf-mx-8 { margin-inline: var(--pf-space-8); }
  .pf-mx-9 { margin-inline: var(--pf-space-9); }
  .pf-mx-auto { margin-inline: auto; }
  .pf-mx-px { margin-inline: 1px; }
  
  .pf-my-0 { margin-block: 0; }
  .pf-my-1 { margin-block: var(--pf-space-1); }
  .pf-my-2 { margin-block: var(--pf-space-2); }
  .pf-my-3 { margin-block: var(--pf-space-3); }
  .pf-my-4 { margin-block: var(--pf-space-4); }
  .pf-my-5 { margin-block: var(--pf-space-5); }
  .pf-my-6 { margin-block: var(--pf-space-6); }
  .pf-my-7 { margin-block: var(--pf-space-7); }
  .pf-my-8 { margin-block: var(--pf-space-8); }
  .pf-my-9 { margin-block: var(--pf-space-9); }
  .pf-my-auto { margin-block: auto; }
  .pf-my-px { margin-block: 1px; }
  
  .pf-mt-0 { margin-top: 0; }
  .pf-mt-1 { margin-top: var(--pf-space-1); }
  .pf-mt-2 { margin-top: var(--pf-space-2); }
  .pf-mt-3 { margin-top: var(--pf-space-3); }
  .pf-mt-4 { margin-top: var(--pf-space-4); }
  .pf-mt-5 { margin-top: var(--pf-space-5); }
  .pf-mt-6 { margin-top: var(--pf-space-6); }
  .pf-mt-7 { margin-top: var(--pf-space-7); }
  .pf-mt-8 { margin-top: var(--pf-space-8); }
  .pf-mt-9 { margin-top: var(--pf-space-9); }
  .pf-mt-auto { margin-top: auto; }
  .pf-mt-px { margin-top: 1px; }
  
  .pf-me-0 { margin-inline-end: 0; }
  .pf-me-1 { margin-inline-end: var(--pf-space-1); }
  .pf-me-2 { margin-inline-end: var(--pf-space-2); }
  .pf-me-3 { margin-inline-end: var(--pf-space-3); }
  .pf-me-4 { margin-inline-end: var(--pf-space-4); }
  .pf-me-5 { margin-inline-end: var(--pf-space-5); }
  .pf-me-6 { margin-inline-end: var(--pf-space-6); }
  .pf-me-7 { margin-inline-end: var(--pf-space-7); }
  .pf-me-8 { margin-inline-end: var(--pf-space-8); }
  .pf-me-9 { margin-inline-end: var(--pf-space-9); }
  .pf-me-auto { margin-inline-end: auto; }
  .pf-me-px { margin-inline-end: 1px; }
  
  .pf-mb-0 { margin-bottom: 0; }
  .pf-mb-1 { margin-bottom: var(--pf-space-1); }
  .pf-mb-2 { margin-bottom: var(--pf-space-2); }
  .pf-mb-3 { margin-bottom: var(--pf-space-3); }
  .pf-mb-4 { margin-bottom: var(--pf-space-4); }
  .pf-mb-5 { margin-bottom: var(--pf-space-5); }
  .pf-mb-6 { margin-bottom: var(--pf-space-6); }
  .pf-mb-7 { margin-bottom: var(--pf-space-7); }
  .pf-mb-8 { margin-bottom: var(--pf-space-8); }
  .pf-mb-9 { margin-bottom: var(--pf-space-9); }
  .pf-mb-auto { margin-bottom: auto; }
  .pf-mb-px { margin-bottom: 1px; }
  
  .pf-ms-0 { margin-inline-start: 0; }
  .pf-ms-1 { margin-inline-start: var(--pf-space-1); }
  .pf-ms-2 { margin-inline-start: var(--pf-space-2); }
  .pf-ms-3 { margin-inline-start: var(--pf-space-3); }
  .pf-ms-4 { margin-inline-start: var(--pf-space-4); }
  .pf-ms-5 { margin-inline-start: var(--pf-space-5); }
  .pf-ms-6 { margin-inline-start: var(--pf-space-6); }
  .pf-ms-7 { margin-inline-start: var(--pf-space-7); }
  .pf-ms-8 { margin-inline-start: var(--pf-space-8); }
  .pf-ms-9 { margin-inline-start: var(--pf-space-9); }
  .pf-ms-auto { margin-inline-start: auto; }
  .pf-ms-px { margin-inline-start: 1px; }
  
  
  /* ==========================================================================
     #GAP
     ==========================================================================
     Works on any flex or grid parent, including the Core primitives:
       <div class="pf-cluster pf-gap-2"> ... </div>
     ========================================================================== */
  
  .pf-gap-0 { gap: 0; }
  .pf-gap-1 { gap: var(--pf-space-1); }
  .pf-gap-2 { gap: var(--pf-space-2); }
  .pf-gap-3 { gap: var(--pf-space-3); }
  .pf-gap-4 { gap: var(--pf-space-4); }
  .pf-gap-5 { gap: var(--pf-space-5); }
  .pf-gap-6 { gap: var(--pf-space-6); }
  .pf-gap-7 { gap: var(--pf-space-7); }
  .pf-gap-8 { gap: var(--pf-space-8); }
  .pf-gap-9 { gap: var(--pf-space-9); }
  .pf-gap-px { gap: 1px; }
  
  .pf-gap-x-0 { column-gap: 0; }
  .pf-gap-x-1 { column-gap: var(--pf-space-1); }
  .pf-gap-x-2 { column-gap: var(--pf-space-2); }
  .pf-gap-x-3 { column-gap: var(--pf-space-3); }
  .pf-gap-x-4 { column-gap: var(--pf-space-4); }
  .pf-gap-x-5 { column-gap: var(--pf-space-5); }
  .pf-gap-x-6 { column-gap: var(--pf-space-6); }
  .pf-gap-x-7 { column-gap: var(--pf-space-7); }
  .pf-gap-x-8 { column-gap: var(--pf-space-8); }
  .pf-gap-x-9 { column-gap: var(--pf-space-9); }
  .pf-gap-x-px { column-gap: 1px; }
  
  .pf-gap-y-0 { row-gap: 0; }
  .pf-gap-y-1 { row-gap: var(--pf-space-1); }
  .pf-gap-y-2 { row-gap: var(--pf-space-2); }
  .pf-gap-y-3 { row-gap: var(--pf-space-3); }
  .pf-gap-y-4 { row-gap: var(--pf-space-4); }
  .pf-gap-y-5 { row-gap: var(--pf-space-5); }
  .pf-gap-y-6 { row-gap: var(--pf-space-6); }
  .pf-gap-y-7 { row-gap: var(--pf-space-7); }
  .pf-gap-y-8 { row-gap: var(--pf-space-8); }
  .pf-gap-y-9 { row-gap: var(--pf-space-9); }
  .pf-gap-y-px { row-gap: 1px; }
  
  .pf-gap-fluid { gap: var(--pf-gap); }
  .pf-gap-fluid-lg { gap: var(--pf-gap-lg); }
  
  /* ==========================================================================
     #GRID TRACKS AND PLACEMENT
     ==========================================================================
     Shorthands for a one-off grid that does not need the twelve-column system.
     .pf-cols-3 is three equal tracks that do NOT collapse on their own - use
     .pf-grid--3 from Core when you want the responsive behaviour handled.
     ========================================================================== */
  
  .pf-cols-1 { display: grid; grid-template-columns: repeat(1, minmax(0, 1fr)); }
  .pf-cols-2 { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .pf-cols-3 { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .pf-cols-4 { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); }
  .pf-cols-5 { display: grid; grid-template-columns: repeat(5, minmax(0, 1fr)); }
  .pf-cols-6 { display: grid; grid-template-columns: repeat(6, minmax(0, 1fr)); }
  .pf-cols-12 { display: grid; grid-template-columns: repeat(12, minmax(0, 1fr)); }
  .pf-cols-auto { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(var(--pf-min, 260px), 100%), 1fr)); }
  .pf-cols-sidebar { display: grid; grid-template-columns: auto minmax(0, 1fr); }
  
  .pf-span-1 { grid-column: span 1; }
  .pf-span-2 { grid-column: span 2; }
  .pf-span-3 { grid-column: span 3; }
  .pf-span-4 { grid-column: span 4; }
  .pf-span-6 { grid-column: span 6; }
  .pf-row-span-2 { grid-row: span 2; }
  
  .pf-place-center { place-items: center; }
  .pf-place-start { place-items: start; }
  .pf-place-end { place-items: end; }
  .pf-self-start { align-self: start; }
  .pf-self-center { align-self: center; }
  .pf-self-end { align-self: end; }
  .pf-self-stretch { align-self: stretch; }
  .pf-content-between { align-content: space-between; }
  .pf-content-start { align-content: start; }
  
  /* ==========================================================================
     #PROPORTIONAL WIDTHS
     ==========================================================================
     Percentages in steps of five, plus the common fractions.
  
     These exist for a specific reason: a progress bar, a meter or a chart
     column is data, and the obvious way to express data is an inline style.
     A strict Content-Security-Policy forbids inline styles outright, so a
     framework that leaves you no other option has quietly forced you to
     weaken your policy. Twenty-one classes are cheaper than 'unsafe-inline'.
  
     For a value that genuinely needs single-percent precision, set
     --pf-progress-value in a stylesheet you control rather than on the element.
     ========================================================================== */
  
  .pf-w-0 { width: 0%; }
  .pf-w-5 { width: 5%; }
  .pf-w-10 { width: 10%; }
  .pf-w-15 { width: 15%; }
  .pf-w-20 { width: 20%; }
  .pf-w-25 { width: 25%; }
  .pf-w-30 { width: 30%; }
  .pf-w-35 { width: 35%; }
  .pf-w-40 { width: 40%; }
  .pf-w-45 { width: 45%; }
  .pf-w-50 { width: 50%; }
  .pf-w-55 { width: 55%; }
  .pf-w-60 { width: 60%; }
  .pf-w-65 { width: 65%; }
  .pf-w-70 { width: 70%; }
  .pf-w-75 { width: 75%; }
  .pf-w-80 { width: 80%; }
  .pf-w-85 { width: 85%; }
  .pf-w-90 { width: 90%; }
  .pf-w-95 { width: 95%; }
  .pf-w-100 { width: 100%; }
  
  .pf-w-1-2 { width: 50%; }
  .pf-w-1-3 { width: 33.3333%; }
  .pf-w-2-3 { width: 66.6667%; }
  .pf-w-1-4 { width: 25%; }
  .pf-w-3-4 { width: 75%; }
  .pf-w-1-5 { width: 20%; }
  .pf-w-2-5 { width: 40%; }
  .pf-w-3-5 { width: 60%; }
  .pf-w-4-5 { width: 80%; }
  
  /* ==========================================================================
     #FLEX SIZING
     ========================================================================== */
  
  .pf-flex-1 { flex: 1 1 0%; }
  .pf-flex-auto { flex: 1 1 auto; }
  .pf-flex-initial { flex: 0 1 auto; }
  .pf-flex-none { flex: none; }
  .pf-grow-0 { flex-grow: 0; }
  .pf-grow-1 { flex-grow: 1; }
  .pf-shrink-1 { flex-shrink: 1; }
  .pf-basis-0 { flex-basis: 0; }
  .pf-basis-auto { flex-basis: auto; }
  .pf-basis-full { flex-basis: 100%; }
  .pf-basis-half { flex-basis: 50%; }
  
  
  /* ==========================================================================
     #RESPONSIVE SPACING
     ==========================================================================
     Only the six most-used families are generated per breakpoint - padding,
     block and inline padding, margin top and bottom, and gap. Generating all
     eighty at five breakpoints is how a utility file reaches 300 KB and a
     build step stops being optional.
     ========================================================================== */
  
  @media (min-width: 576px) {
    .pf-sm-p-0 { padding: 0; }
    .pf-sm-px-0 { padding-inline: 0; }
    .pf-sm-py-0 { padding-block: 0; }
    .pf-sm-mt-0 { margin-top: 0; }
    .pf-sm-mb-0 { margin-bottom: 0; }
    .pf-sm-gap-0 { gap: 0; }
    .pf-sm-p-1 { padding: var(--pf-space-1); }
    .pf-sm-px-1 { padding-inline: var(--pf-space-1); }
    .pf-sm-py-1 { padding-block: var(--pf-space-1); }
    .pf-sm-mt-1 { margin-top: var(--pf-space-1); }
    .pf-sm-mb-1 { margin-bottom: var(--pf-space-1); }
    .pf-sm-gap-1 { gap: var(--pf-space-1); }
    .pf-sm-p-2 { padding: var(--pf-space-2); }
    .pf-sm-px-2 { padding-inline: var(--pf-space-2); }
    .pf-sm-py-2 { padding-block: var(--pf-space-2); }
    .pf-sm-mt-2 { margin-top: var(--pf-space-2); }
    .pf-sm-mb-2 { margin-bottom: var(--pf-space-2); }
    .pf-sm-gap-2 { gap: var(--pf-space-2); }
    .pf-sm-p-3 { padding: var(--pf-space-3); }
    .pf-sm-px-3 { padding-inline: var(--pf-space-3); }
    .pf-sm-py-3 { padding-block: var(--pf-space-3); }
    .pf-sm-mt-3 { margin-top: var(--pf-space-3); }
    .pf-sm-mb-3 { margin-bottom: var(--pf-space-3); }
    .pf-sm-gap-3 { gap: var(--pf-space-3); }
    .pf-sm-p-4 { padding: var(--pf-space-4); }
    .pf-sm-px-4 { padding-inline: var(--pf-space-4); }
    .pf-sm-py-4 { padding-block: var(--pf-space-4); }
    .pf-sm-mt-4 { margin-top: var(--pf-space-4); }
    .pf-sm-mb-4 { margin-bottom: var(--pf-space-4); }
    .pf-sm-gap-4 { gap: var(--pf-space-4); }
    .pf-sm-p-5 { padding: var(--pf-space-5); }
    .pf-sm-px-5 { padding-inline: var(--pf-space-5); }
    .pf-sm-py-5 { padding-block: var(--pf-space-5); }
    .pf-sm-mt-5 { margin-top: var(--pf-space-5); }
    .pf-sm-mb-5 { margin-bottom: var(--pf-space-5); }
    .pf-sm-gap-5 { gap: var(--pf-space-5); }
    .pf-sm-p-6 { padding: var(--pf-space-6); }
    .pf-sm-px-6 { padding-inline: var(--pf-space-6); }
    .pf-sm-py-6 { padding-block: var(--pf-space-6); }
    .pf-sm-mt-6 { margin-top: var(--pf-space-6); }
    .pf-sm-mb-6 { margin-bottom: var(--pf-space-6); }
    .pf-sm-gap-6 { gap: var(--pf-space-6); }
    .pf-sm-p-7 { padding: var(--pf-space-7); }
    .pf-sm-px-7 { padding-inline: var(--pf-space-7); }
    .pf-sm-py-7 { padding-block: var(--pf-space-7); }
    .pf-sm-mt-7 { margin-top: var(--pf-space-7); }
    .pf-sm-mb-7 { margin-bottom: var(--pf-space-7); }
    .pf-sm-gap-7 { gap: var(--pf-space-7); }
    .pf-sm-p-8 { padding: var(--pf-space-8); }
    .pf-sm-px-8 { padding-inline: var(--pf-space-8); }
    .pf-sm-py-8 { padding-block: var(--pf-space-8); }
    .pf-sm-mt-8 { margin-top: var(--pf-space-8); }
    .pf-sm-mb-8 { margin-bottom: var(--pf-space-8); }
    .pf-sm-gap-8 { gap: var(--pf-space-8); }
    .pf-sm-p-9 { padding: var(--pf-space-9); }
    .pf-sm-px-9 { padding-inline: var(--pf-space-9); }
    .pf-sm-py-9 { padding-block: var(--pf-space-9); }
    .pf-sm-mt-9 { margin-top: var(--pf-space-9); }
    .pf-sm-mb-9 { margin-bottom: var(--pf-space-9); }
    .pf-sm-gap-9 { gap: var(--pf-space-9); }
    .pf-sm-p-px { padding: 1px; }
    .pf-sm-px-px { padding-inline: 1px; }
    .pf-sm-py-px { padding-block: 1px; }
    .pf-sm-mt-px { margin-top: 1px; }
    .pf-sm-mb-px { margin-bottom: 1px; }
    .pf-sm-gap-px { gap: 1px; }
    .pf-sm-cols-1 { display: grid; grid-template-columns: repeat(1, minmax(0, 1fr)); }
    .pf-sm-cols-2 { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); }
    .pf-sm-cols-3 { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); }
    .pf-sm-cols-4 { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); }
    .pf-sm-cols-6 { display: grid; grid-template-columns: repeat(6, minmax(0, 1fr)); }
  }
  
  @media (min-width: 768px) {
    .pf-md-p-0 { padding: 0; }
    .pf-md-px-0 { padding-inline: 0; }
    .pf-md-py-0 { padding-block: 0; }
    .pf-md-mt-0 { margin-top: 0; }
    .pf-md-mb-0 { margin-bottom: 0; }
    .pf-md-gap-0 { gap: 0; }
    .pf-md-p-1 { padding: var(--pf-space-1); }
    .pf-md-px-1 { padding-inline: var(--pf-space-1); }
    .pf-md-py-1 { padding-block: var(--pf-space-1); }
    .pf-md-mt-1 { margin-top: var(--pf-space-1); }
    .pf-md-mb-1 { margin-bottom: var(--pf-space-1); }
    .pf-md-gap-1 { gap: var(--pf-space-1); }
    .pf-md-p-2 { padding: var(--pf-space-2); }
    .pf-md-px-2 { padding-inline: var(--pf-space-2); }
    .pf-md-py-2 { padding-block: var(--pf-space-2); }
    .pf-md-mt-2 { margin-top: var(--pf-space-2); }
    .pf-md-mb-2 { margin-bottom: var(--pf-space-2); }
    .pf-md-gap-2 { gap: var(--pf-space-2); }
    .pf-md-p-3 { padding: var(--pf-space-3); }
    .pf-md-px-3 { padding-inline: var(--pf-space-3); }
    .pf-md-py-3 { padding-block: var(--pf-space-3); }
    .pf-md-mt-3 { margin-top: var(--pf-space-3); }
    .pf-md-mb-3 { margin-bottom: var(--pf-space-3); }
    .pf-md-gap-3 { gap: var(--pf-space-3); }
    .pf-md-p-4 { padding: var(--pf-space-4); }
    .pf-md-px-4 { padding-inline: var(--pf-space-4); }
    .pf-md-py-4 { padding-block: var(--pf-space-4); }
    .pf-md-mt-4 { margin-top: var(--pf-space-4); }
    .pf-md-mb-4 { margin-bottom: var(--pf-space-4); }
    .pf-md-gap-4 { gap: var(--pf-space-4); }
    .pf-md-p-5 { padding: var(--pf-space-5); }
    .pf-md-px-5 { padding-inline: var(--pf-space-5); }
    .pf-md-py-5 { padding-block: var(--pf-space-5); }
    .pf-md-mt-5 { margin-top: var(--pf-space-5); }
    .pf-md-mb-5 { margin-bottom: var(--pf-space-5); }
    .pf-md-gap-5 { gap: var(--pf-space-5); }
    .pf-md-p-6 { padding: var(--pf-space-6); }
    .pf-md-px-6 { padding-inline: var(--pf-space-6); }
    .pf-md-py-6 { padding-block: var(--pf-space-6); }
    .pf-md-mt-6 { margin-top: var(--pf-space-6); }
    .pf-md-mb-6 { margin-bottom: var(--pf-space-6); }
    .pf-md-gap-6 { gap: var(--pf-space-6); }
    .pf-md-p-7 { padding: var(--pf-space-7); }
    .pf-md-px-7 { padding-inline: var(--pf-space-7); }
    .pf-md-py-7 { padding-block: var(--pf-space-7); }
    .pf-md-mt-7 { margin-top: var(--pf-space-7); }
    .pf-md-mb-7 { margin-bottom: var(--pf-space-7); }
    .pf-md-gap-7 { gap: var(--pf-space-7); }
    .pf-md-p-8 { padding: var(--pf-space-8); }
    .pf-md-px-8 { padding-inline: var(--pf-space-8); }
    .pf-md-py-8 { padding-block: var(--pf-space-8); }
    .pf-md-mt-8 { margin-top: var(--pf-space-8); }
    .pf-md-mb-8 { margin-bottom: var(--pf-space-8); }
    .pf-md-gap-8 { gap: var(--pf-space-8); }
    .pf-md-p-9 { padding: var(--pf-space-9); }
    .pf-md-px-9 { padding-inline: var(--pf-space-9); }
    .pf-md-py-9 { padding-block: var(--pf-space-9); }
    .pf-md-mt-9 { margin-top: var(--pf-space-9); }
    .pf-md-mb-9 { margin-bottom: var(--pf-space-9); }
    .pf-md-gap-9 { gap: var(--pf-space-9); }
    .pf-md-p-px { padding: 1px; }
    .pf-md-px-px { padding-inline: 1px; }
    .pf-md-py-px { padding-block: 1px; }
    .pf-md-mt-px { margin-top: 1px; }
    .pf-md-mb-px { margin-bottom: 1px; }
    .pf-md-gap-px { gap: 1px; }
    .pf-md-cols-1 { display: grid; grid-template-columns: repeat(1, minmax(0, 1fr)); }
    .pf-md-cols-2 { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); }
    .pf-md-cols-3 { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); }
    .pf-md-cols-4 { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); }
    .pf-md-cols-6 { display: grid; grid-template-columns: repeat(6, minmax(0, 1fr)); }
  }
  
  @media (min-width: 992px) {
    .pf-lg-p-0 { padding: 0; }
    .pf-lg-px-0 { padding-inline: 0; }
    .pf-lg-py-0 { padding-block: 0; }
    .pf-lg-mt-0 { margin-top: 0; }
    .pf-lg-mb-0 { margin-bottom: 0; }
    .pf-lg-gap-0 { gap: 0; }
    .pf-lg-p-1 { padding: var(--pf-space-1); }
    .pf-lg-px-1 { padding-inline: var(--pf-space-1); }
    .pf-lg-py-1 { padding-block: var(--pf-space-1); }
    .pf-lg-mt-1 { margin-top: var(--pf-space-1); }
    .pf-lg-mb-1 { margin-bottom: var(--pf-space-1); }
    .pf-lg-gap-1 { gap: var(--pf-space-1); }
    .pf-lg-p-2 { padding: var(--pf-space-2); }
    .pf-lg-px-2 { padding-inline: var(--pf-space-2); }
    .pf-lg-py-2 { padding-block: var(--pf-space-2); }
    .pf-lg-mt-2 { margin-top: var(--pf-space-2); }
    .pf-lg-mb-2 { margin-bottom: var(--pf-space-2); }
    .pf-lg-gap-2 { gap: var(--pf-space-2); }
    .pf-lg-p-3 { padding: var(--pf-space-3); }
    .pf-lg-px-3 { padding-inline: var(--pf-space-3); }
    .pf-lg-py-3 { padding-block: var(--pf-space-3); }
    .pf-lg-mt-3 { margin-top: var(--pf-space-3); }
    .pf-lg-mb-3 { margin-bottom: var(--pf-space-3); }
    .pf-lg-gap-3 { gap: var(--pf-space-3); }
    .pf-lg-p-4 { padding: var(--pf-space-4); }
    .pf-lg-px-4 { padding-inline: var(--pf-space-4); }
    .pf-lg-py-4 { padding-block: var(--pf-space-4); }
    .pf-lg-mt-4 { margin-top: var(--pf-space-4); }
    .pf-lg-mb-4 { margin-bottom: var(--pf-space-4); }
    .pf-lg-gap-4 { gap: var(--pf-space-4); }
    .pf-lg-p-5 { padding: var(--pf-space-5); }
    .pf-lg-px-5 { padding-inline: var(--pf-space-5); }
    .pf-lg-py-5 { padding-block: var(--pf-space-5); }
    .pf-lg-mt-5 { margin-top: var(--pf-space-5); }
    .pf-lg-mb-5 { margin-bottom: var(--pf-space-5); }
    .pf-lg-gap-5 { gap: var(--pf-space-5); }
    .pf-lg-p-6 { padding: var(--pf-space-6); }
    .pf-lg-px-6 { padding-inline: var(--pf-space-6); }
    .pf-lg-py-6 { padding-block: var(--pf-space-6); }
    .pf-lg-mt-6 { margin-top: var(--pf-space-6); }
    .pf-lg-mb-6 { margin-bottom: var(--pf-space-6); }
    .pf-lg-gap-6 { gap: var(--pf-space-6); }
    .pf-lg-p-7 { padding: var(--pf-space-7); }
    .pf-lg-px-7 { padding-inline: var(--pf-space-7); }
    .pf-lg-py-7 { padding-block: var(--pf-space-7); }
    .pf-lg-mt-7 { margin-top: var(--pf-space-7); }
    .pf-lg-mb-7 { margin-bottom: var(--pf-space-7); }
    .pf-lg-gap-7 { gap: var(--pf-space-7); }
    .pf-lg-p-8 { padding: var(--pf-space-8); }
    .pf-lg-px-8 { padding-inline: var(--pf-space-8); }
    .pf-lg-py-8 { padding-block: var(--pf-space-8); }
    .pf-lg-mt-8 { margin-top: var(--pf-space-8); }
    .pf-lg-mb-8 { margin-bottom: var(--pf-space-8); }
    .pf-lg-gap-8 { gap: var(--pf-space-8); }
    .pf-lg-p-9 { padding: var(--pf-space-9); }
    .pf-lg-px-9 { padding-inline: var(--pf-space-9); }
    .pf-lg-py-9 { padding-block: var(--pf-space-9); }
    .pf-lg-mt-9 { margin-top: var(--pf-space-9); }
    .pf-lg-mb-9 { margin-bottom: var(--pf-space-9); }
    .pf-lg-gap-9 { gap: var(--pf-space-9); }
    .pf-lg-p-px { padding: 1px; }
    .pf-lg-px-px { padding-inline: 1px; }
    .pf-lg-py-px { padding-block: 1px; }
    .pf-lg-mt-px { margin-top: 1px; }
    .pf-lg-mb-px { margin-bottom: 1px; }
    .pf-lg-gap-px { gap: 1px; }
    .pf-lg-cols-1 { display: grid; grid-template-columns: repeat(1, minmax(0, 1fr)); }
    .pf-lg-cols-2 { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); }
    .pf-lg-cols-3 { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); }
    .pf-lg-cols-4 { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); }
    .pf-lg-cols-6 { display: grid; grid-template-columns: repeat(6, minmax(0, 1fr)); }
  }
  
  @media (min-width: 1200px) {
    .pf-xl-p-0 { padding: 0; }
    .pf-xl-px-0 { padding-inline: 0; }
    .pf-xl-py-0 { padding-block: 0; }
    .pf-xl-mt-0 { margin-top: 0; }
    .pf-xl-mb-0 { margin-bottom: 0; }
    .pf-xl-gap-0 { gap: 0; }
    .pf-xl-p-1 { padding: var(--pf-space-1); }
    .pf-xl-px-1 { padding-inline: var(--pf-space-1); }
    .pf-xl-py-1 { padding-block: var(--pf-space-1); }
    .pf-xl-mt-1 { margin-top: var(--pf-space-1); }
    .pf-xl-mb-1 { margin-bottom: var(--pf-space-1); }
    .pf-xl-gap-1 { gap: var(--pf-space-1); }
    .pf-xl-p-2 { padding: var(--pf-space-2); }
    .pf-xl-px-2 { padding-inline: var(--pf-space-2); }
    .pf-xl-py-2 { padding-block: var(--pf-space-2); }
    .pf-xl-mt-2 { margin-top: var(--pf-space-2); }
    .pf-xl-mb-2 { margin-bottom: var(--pf-space-2); }
    .pf-xl-gap-2 { gap: var(--pf-space-2); }
    .pf-xl-p-3 { padding: var(--pf-space-3); }
    .pf-xl-px-3 { padding-inline: var(--pf-space-3); }
    .pf-xl-py-3 { padding-block: var(--pf-space-3); }
    .pf-xl-mt-3 { margin-top: var(--pf-space-3); }
    .pf-xl-mb-3 { margin-bottom: var(--pf-space-3); }
    .pf-xl-gap-3 { gap: var(--pf-space-3); }
    .pf-xl-p-4 { padding: var(--pf-space-4); }
    .pf-xl-px-4 { padding-inline: var(--pf-space-4); }
    .pf-xl-py-4 { padding-block: var(--pf-space-4); }
    .pf-xl-mt-4 { margin-top: var(--pf-space-4); }
    .pf-xl-mb-4 { margin-bottom: var(--pf-space-4); }
    .pf-xl-gap-4 { gap: var(--pf-space-4); }
    .pf-xl-p-5 { padding: var(--pf-space-5); }
    .pf-xl-px-5 { padding-inline: var(--pf-space-5); }
    .pf-xl-py-5 { padding-block: var(--pf-space-5); }
    .pf-xl-mt-5 { margin-top: var(--pf-space-5); }
    .pf-xl-mb-5 { margin-bottom: var(--pf-space-5); }
    .pf-xl-gap-5 { gap: var(--pf-space-5); }
    .pf-xl-p-6 { padding: var(--pf-space-6); }
    .pf-xl-px-6 { padding-inline: var(--pf-space-6); }
    .pf-xl-py-6 { padding-block: var(--pf-space-6); }
    .pf-xl-mt-6 { margin-top: var(--pf-space-6); }
    .pf-xl-mb-6 { margin-bottom: var(--pf-space-6); }
    .pf-xl-gap-6 { gap: var(--pf-space-6); }
    .pf-xl-p-7 { padding: var(--pf-space-7); }
    .pf-xl-px-7 { padding-inline: var(--pf-space-7); }
    .pf-xl-py-7 { padding-block: var(--pf-space-7); }
    .pf-xl-mt-7 { margin-top: var(--pf-space-7); }
    .pf-xl-mb-7 { margin-bottom: var(--pf-space-7); }
    .pf-xl-gap-7 { gap: var(--pf-space-7); }
    .pf-xl-p-8 { padding: var(--pf-space-8); }
    .pf-xl-px-8 { padding-inline: var(--pf-space-8); }
    .pf-xl-py-8 { padding-block: var(--pf-space-8); }
    .pf-xl-mt-8 { margin-top: var(--pf-space-8); }
    .pf-xl-mb-8 { margin-bottom: var(--pf-space-8); }
    .pf-xl-gap-8 { gap: var(--pf-space-8); }
    .pf-xl-p-9 { padding: var(--pf-space-9); }
    .pf-xl-px-9 { padding-inline: var(--pf-space-9); }
    .pf-xl-py-9 { padding-block: var(--pf-space-9); }
    .pf-xl-mt-9 { margin-top: var(--pf-space-9); }
    .pf-xl-mb-9 { margin-bottom: var(--pf-space-9); }
    .pf-xl-gap-9 { gap: var(--pf-space-9); }
    .pf-xl-p-px { padding: 1px; }
    .pf-xl-px-px { padding-inline: 1px; }
    .pf-xl-py-px { padding-block: 1px; }
    .pf-xl-mt-px { margin-top: 1px; }
    .pf-xl-mb-px { margin-bottom: 1px; }
    .pf-xl-gap-px { gap: 1px; }
    .pf-xl-cols-1 { display: grid; grid-template-columns: repeat(1, minmax(0, 1fr)); }
    .pf-xl-cols-2 { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); }
    .pf-xl-cols-3 { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); }
    .pf-xl-cols-4 { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); }
    .pf-xl-cols-6 { display: grid; grid-template-columns: repeat(6, minmax(0, 1fr)); }
  }
}

/* ===== PolyFishCSS-Effects.css ===== */
/*! PolyFishCSS-Effects.css | v1.0.0-rc.2-rc.1-rc.1-rc.1-rc.1-rc.1 | polyfish.org | MIT
 *
 * Visual effect utilities: transforms, filters, gradients, rings, animations,
 * scroll behaviour and the group/peer interaction patterns.
 *
 * Depends on: PolyFishCSS-Core.css (tokens, motion easing, accent roles).
 * Load order: after Core, with the other utility files at the end.
 *
 * CONTENTS
 *   1. Transforms
 *   2. Filters and backdrop
 *   3. Gradients
 *   4. Rings and outlines
 *   5. Animations
 *   6. Transition control
 *   7. Scroll behaviour
 *   8. Group and focus-within
 *   9. Blend, isolation and misc
 *
 * MOTION POLICY
 *   Every animation in this file is wrapped in prefers-reduced-motion. Core's
 *   global block already neutralises durations, but that leaves an element
 *   stuck at whatever the first keyframe said - so animations that start at
 *   opacity 0 are not merely slowed here, they are not applied at all.
 */

@layer polyfish.core, polyfish.grid, polyfish.headers, polyfish.content, polyfish.forms, polyfish.components, polyfish.footers, polyfish.space, polyfish.effects, polyfish.utilities, polyfish.fonts, polyfish.compat;

/* ==========================================================================
   CASCADE LAYER
   ==========================================================================
   Everything below sits in `polyfish.effects`. The layer order is declared in
   every module, so it holds no matter which order you link the files in.

   Why this matters to you: unlayered CSS beats layered CSS regardless of
   specificity. Your own stylesheet overrides any framework rule with a plain
   class selector — no `!important`, no specificity arms race, no worrying
   about whether Utilities loaded last.

     <link rel="stylesheet" href="PolyFishCSS-Core.min.css">
     <link rel="stylesheet" href="my-app.css">   <!-- wins, always -->

   If you want your CSS layered too, name a layer after the framework's:

     @layer polyfish, app;
     @layer app { .card { background: rebeccapurple; } }
   ========================================================================== */

@layer polyfish.effects {
  /* ==========================================================================
     #TRANSFORMS
     ==========================================================================
     Composed through custom properties rather than a single transform
     declaration, so translate, rotate and scale utilities can be combined on
     one element without the last one silently winning.
     ========================================================================== */
  
  .pf-transform,
  [class*="pf-translate-"],
  [class*="pf-rotate-"],
  [class*="pf-scale-"] {
    transform: translate(var(--pf-tx, 0), var(--pf-ty, 0)) rotate(var(--pf-rotate, 0deg))
      scale(var(--pf-scale, 1));
  }
  
  .pf-translate-x-1 { --pf-tx: 0.25rem; }
  .pf-translate-x-2 { --pf-tx: 0.5rem; }
  .pf-translate-x-4 { --pf-tx: 1rem; }
  .pf-translate-y-1 { --pf-ty: 0.25rem; }
  .pf-translate-y-2 { --pf-ty: 0.5rem; }
  .pf-translate-y-4 { --pf-ty: 1rem; }
  .pf-translate-y-up-1 { --pf-ty: -0.25rem; }
  .pf-translate-y-up-2 { --pf-ty: -0.5rem; }
  .pf-translate-center { --pf-tx: -50%; --pf-ty: -50%; }
  
  .pf-rotate-45 { --pf-rotate: 45deg; }
  .pf-rotate-90 { --pf-rotate: 90deg; }
  .pf-rotate-180 { --pf-rotate: 180deg; }
  .pf-rotate-back-45 { --pf-rotate: -45deg; }
  
  .pf-scale-95 { --pf-scale: 0.95; }
  .pf-scale-105 { --pf-scale: 1.05; }
  .pf-scale-110 { --pf-scale: 1.1; }
  
  .pf-flip-x { transform: scaleX(-1); }
  .pf-origin-top { transform-origin: top; }
  .pf-origin-bottom { transform-origin: bottom; }
  .pf-origin-left { transform-origin: left; }
  
  /* ==========================================================================
     #FILTERS AND BACKDROP
     ==========================================================================
     backdrop-filter is expensive on a large surface and on a phone it can cost
     more than it looks worth - use it on a bar or a panel, not a full page.
     ========================================================================== */
  
  .pf-blur-sm { filter: blur(2px); }
  .pf-blur { filter: blur(6px); }
  .pf-blur-lg { filter: blur(16px); }
  .pf-grayscale { filter: grayscale(1); }
  .pf-dim { filter: brightness(0.7); }
  .pf-bright { filter: brightness(1.15); }
  .pf-saturate { filter: saturate(1.3); }
  .pf-desaturate { filter: saturate(0.55); }
  .pf-filter-none { filter: none; }
  
  .pf-backdrop-blur {
    -webkit-backdrop-filter: blur(10px);
    backdrop-filter: blur(10px);
  }
  .pf-backdrop-blur-lg {
    -webkit-backdrop-filter: blur(20px);
    backdrop-filter: blur(20px);
  }
  
  /* A frosted panel that still works where backdrop-filter does not: the solid
     background is declared first and only replaced where the feature exists. */
  .pf-frost { background: var(--pf-bg-deep); }
  @supports ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
    .pf-frost {
      background: color-mix(in srgb, var(--pf-bg-deep) 72%, transparent);
      -webkit-backdrop-filter: blur(14px);
      backdrop-filter: blur(14px);
    }
  }
  
  /* ==========================================================================
     #GRADIENTS
     ==========================================================================
     Built from role tokens, so a gradient follows a theme instead of pinning
     the page to one palette.
     ========================================================================== */
  
  .pf-gradient-surface {
    background-image: linear-gradient(180deg, var(--pf-surface), transparent 70%);
  }
  .pf-gradient-deep {
    background-image: linear-gradient(180deg, var(--pf-bg-deep), var(--pf-bg));
  }
  .pf-gradient-accent {
    background-image: linear-gradient(120deg, var(--pf-accent), var(--pf-accent-2));
  }
  .pf-gradient-edge {
    background-image: linear-gradient(90deg, var(--pf-surface), transparent);
  }
  
  /**
   * Gradient text
   *
   * <h2 class="pf-gradient-text">Headline</h2>
   *
   * The fallback colour is declared first: background-clip: text with a
   * transparent fill produces invisible text where the clip is unsupported, and
   * invisible text is a worse outcome than a flat colour.
   */
  .pf-gradient-text { color: var(--pf-accent); }
  @supports (background-clip: text) or (-webkit-background-clip: text) {
    .pf-gradient-text {
      background-image: linear-gradient(100deg, var(--pf-accent), var(--pf-accent-2));
      -webkit-background-clip: text;
      background-clip: text;
      color: transparent;
    }
  }
  
  /* A hairline rule that fades at both ends. */
  .pf-rule-fade {
    height: 1px;
    border: 0;
    background-image: linear-gradient(90deg, transparent, var(--pf-border-strong), transparent);
  }
  
  /* ==========================================================================
     #RINGS AND OUTLINES
     ==========================================================================
     A ring is a box-shadow, so it follows border-radius and costs no layout.
     An offset ring needs two shadows: the inner one paints the gap in the page
     colour, which is why --pf-ring-offset-color exists.
     ========================================================================== */
  
  .pf-ring-1 { box-shadow: 0 0 0 1px var(--pf-ring-color, var(--pf-border-strong)); }
  .pf-ring-2 { box-shadow: 0 0 0 2px var(--pf-ring-color, var(--pf-border-strong)); }
  .pf-ring-accent { --pf-ring-color: var(--pf-accent); }
  .pf-ring-danger { --pf-ring-color: #e08f8f; }
  .pf-ring-offset {
    box-shadow: 0 0 0 2px var(--pf-ring-offset-color, var(--pf-bg)),
      0 0 0 4px var(--pf-ring-color, var(--pf-accent));
  }
  
  /* ==========================================================================
     #ANIMATIONS
     ==========================================================================
     Five named animations, all opt-in. Each is defined only inside the
     reduced-motion guard, so an element that starts invisible never gets
     stranded there when motion is turned off.
     ========================================================================== */
  
  @media (prefers-reduced-motion: no-preference) {
    .pf-animate-spin { animation: pf-spin 1s linear infinite; }
    .pf-animate-pulse { animation: pf-pulse 2s var(--pf-ease) infinite; }
    .pf-animate-bounce { animation: pf-bounce 1s infinite; }
    .pf-animate-fade { animation: pf-fade-in 400ms var(--pf-ease) both; }
    .pf-animate-rise { animation: pf-rise 400ms var(--pf-ease) both; }
    .pf-animate-slide-in { animation: pf-slide-in 300ms var(--pf-ease) both; }
  
    .pf-delay-1 { animation-delay: 80ms; }
    .pf-delay-2 { animation-delay: 160ms; }
    .pf-delay-3 { animation-delay: 240ms; }
    .pf-delay-4 { animation-delay: 320ms; }
  }
  
  @keyframes pf-pulse {
    0%, 100% { opacity: 1; }
    50% { opacity: 0.55; }
  }
  @keyframes pf-bounce {
    0%, 100% { transform: translateY(-15%); animation-timing-function: cubic-bezier(0.8, 0, 1, 1); }
    50% { transform: none; animation-timing-function: cubic-bezier(0, 0, 0.2, 1); }
  }
  @keyframes pf-rise {
    from { opacity: 0; transform: translateY(0.75rem); }
    to { opacity: 1; transform: none; }
  }
  @keyframes pf-slide-in {
    from { opacity: 0; transform: translateX(-0.75rem); }
    to { opacity: 1; transform: none; }
  }
  
  /* ==========================================================================
     #TRANSITION CONTROL
     ========================================================================== */
  
  .pf-duration-fast { transition-duration: 90ms; }
  .pf-duration-slow { transition-duration: 320ms; }
  .pf-duration-slower { transition-duration: 600ms; }
  .pf-ease-out { transition-timing-function: cubic-bezier(0, 0, 0.2, 1); }
  .pf-ease-in { transition-timing-function: cubic-bezier(0.4, 0, 1, 1); }
  .pf-ease-spring { transition-timing-function: cubic-bezier(0.34, 1.56, 0.64, 1); }
  .pf-transition-transform { transition: transform var(--pf-speed) var(--pf-ease); }
  .pf-transition-opacity { transition: opacity var(--pf-speed) var(--pf-ease); }
  .pf-transition-shadow { transition: box-shadow var(--pf-speed) var(--pf-ease); }
  
  /* ==========================================================================
     #SCROLL BEHAVIOUR
     ========================================================================== */
  
  .pf-snap-x { scroll-snap-type: x mandatory; overscroll-behavior-x: contain; }
  .pf-snap-y { scroll-snap-type: y mandatory; overscroll-behavior-y: contain; }
  .pf-snap-start { scroll-snap-align: start; }
  .pf-snap-center { scroll-snap-align: center; }
  .pf-snap-none { scroll-snap-align: none; }
  .pf-scroll-smooth { scroll-behavior: smooth; }
  .pf-scroll-contain { overscroll-behavior: contain; }
  .pf-scrollbar-thin { scrollbar-width: thin; }
  .pf-scrollbar-none { scrollbar-width: none; }
  .pf-scrollbar-none::-webkit-scrollbar { display: none; }
  .pf-scroll-mt { scroll-margin-top: 6rem; }
  
  /* ==========================================================================
     #GROUP AND FOCUS-WITHIN
     ==========================================================================
     The pattern a utility framework needs and CSS has no shorthand for: a child
     reacting to the parent's state.
     ========================================================================== */
  
  /**
   * <article class="pf-group pf-card">
   *   <h3>Title</h3>
   *   <span class="pf-group-show">→</span>
   * </article>
   *
   * The reveal is scoped to (hover: hover) so a touch device shows the affordance
   * permanently rather than hiding it behind a state a finger cannot enter.
   */
  .pf-group-show { opacity: 1; }
  .pf-group-hide { opacity: 0; }
  
  @media (hover: hover) {
    .pf-group .pf-group-show {
      opacity: 0;
      transition: opacity var(--pf-speed) var(--pf-ease), transform var(--pf-speed) var(--pf-ease);
    }
    .pf-group:hover .pf-group-show,
    .pf-group:focus-within .pf-group-show { opacity: 1; }
    .pf-group:hover .pf-group-hide { opacity: 0; }
    .pf-group:hover .pf-group-slide { transform: translateX(0.25rem); }
    .pf-group-slide { transition: transform var(--pf-speed) var(--pf-ease); }
  }
  
  /* Focus-within, which is how a card containing a link announces itself to a
     keyboard user the way hover does to a mouse. */
  .pf-focus-ring:focus-within { box-shadow: var(--pf-ring); }
  .pf-focus-border:focus-within { border-color: var(--pf-accent); }
  
  /* ==========================================================================
     #BLEND, ISOLATION AND MISC
     ========================================================================== */
  
  .pf-isolate { isolation: isolate; }
  .pf-blend-multiply { mix-blend-mode: multiply; }
  .pf-blend-screen { mix-blend-mode: screen; }
  .pf-blend-overlay { mix-blend-mode: overlay; }
  
  .pf-will-change-transform { will-change: transform; }
  .pf-will-change-opacity { will-change: opacity; }
  
  .pf-resize-none { resize: none; }
  .pf-resize-y { resize: vertical; }
  .pf-appearance-none { appearance: none; }
  .pf-accent-color { accent-color: var(--pf-accent); }
  .pf-caret-accent { caret-color: var(--pf-accent); }
  .pf-list-none { list-style: none; }
  .pf-list-disc { list-style: disc; padding-inline-start: 1.25rem; }
  .pf-list-decimal { list-style: decimal; padding-inline-start: 1.4rem; }
  
  /* Mask the bottom of an overflowing block so the cut looks intentional. */
  .pf-fade-bottom {
    -webkit-mask-image: linear-gradient(180deg, #000 70%, transparent);
    mask-image: linear-gradient(180deg, #000 70%, transparent);
  }
  .pf-fade-right {
    -webkit-mask-image: linear-gradient(90deg, #000 80%, transparent);
    mask-image: linear-gradient(90deg, #000 80%, transparent);
  }
}

/* ===== PolyFishCSS-Utilities.css ===== */
/*! PolyFishCSS-Utilities.css | v1.0.0-rc.2-rc.1-rc.1-rc.1-rc.1-rc.1 | polyfish.org | MIT
 *
 * Single-purpose helpers for spacing, alignment, colour and visibility,
 * plus the scroll reveal and print rules. Optional: the first file to drop if
 * your project already has utilities of its own. Nothing depends on it.
 *
 * Depends on: PolyFishCSS-Core.css (reads its tokens).
 * Load order: Core -> Headers -> Content -> Footers -> Utilities.
 *
 * CONTENTS
 *   1. Spacing
 *   2. Gap
 *   3. Display and flow
 *   4. Text
 *   5. Colour
 *   6. Shape
 *   7. Scroll reveal
 *   8. Responsive visibility and print
 *
 * CONVENTIONS
 *   .pf-block / .pf-block__element / .pf-block--modifier.
 *   Components read role tokens, never palette values. See docs/tokens.
 *
 * SCOPE
 *   This is deliberately small - roughly sixty classes, not six thousand. It
 *   exists to stop you writing one-off rules for a 1rem margin, not to let you
 *   build a page out of class strings. If you find a component being assembled
 *   entirely from these, it wants to be a component.
 * 
 * LOAD LAST
 *   Several helpers tie with component rules on specificity (both a single
 *   class), so the cascade decides. Load this file after the others or a
 *   .pf-mt-0 will quietly lose to a component's own margin.
 */

@layer polyfish.core, polyfish.grid, polyfish.headers, polyfish.content, polyfish.forms, polyfish.components, polyfish.footers, polyfish.space, polyfish.effects, polyfish.utilities, polyfish.fonts, polyfish.compat;

/* ==========================================================================
   CASCADE LAYER
   ==========================================================================
   Everything below sits in `polyfish.utilities`. The layer order is declared in
   every module, so it holds no matter which order you link the files in.

   Why this matters to you: unlayered CSS beats layered CSS regardless of
   specificity. Your own stylesheet overrides any framework rule with a plain
   class selector — no `!important`, no specificity arms race, no worrying
   about whether Utilities loaded last.

     <link rel="stylesheet" href="PolyFishCSS-Core.min.css">
     <link rel="stylesheet" href="my-app.css">   <!-- wins, always -->

   If you want your CSS layered too, name a layer after the framework's:

     @layer polyfish, app;
     @layer app { .card { background: rebeccapurple; } }
   ========================================================================== */

@layer polyfish.utilities {
  /* ==========================================================================
     #SPACING LIVES IN THE SPACE MODULE
     ==========================================================================
     Padding, margin, gap and grid-track utilities used to be here. They moved
     to PolyFishCSS-Space.css when that surface grew past a handful of classes,
     and they are not duplicated back: two modules declaring the same class is
     a maintenance trap, because the day they stop agreeing is the day someone
     spends an afternoon in devtools.
  
     If you load Utilities you almost certainly want Space too.
     ========================================================================== */
  
  /* Display and flow */
  .pf-block { display: block; }
  .pf-inline-block { display: inline-block; }
  .pf-flex { display: flex; }
  .pf-inline-flex { display: inline-flex; }
  .pf-grid-d { display: grid; }
  .pf-none { display: none; }
  
  .pf-wrap { flex-wrap: wrap; }
  .pf-nowrap { flex-wrap: nowrap; }
  /* Named -flex-col rather than -col: Grid owns .pf-col for its twelve-column
     system, and two modules cannot claim the same class. */
  .pf-flex-col { flex-direction: column; }
  .pf-flex-row { flex-direction: row; }
  .pf-items-start { align-items: flex-start; }
  .pf-items-center { align-items: center; }
  .pf-items-end { align-items: flex-end; }
  .pf-justify-start { justify-content: flex-start; }
  .pf-justify-center { justify-content: center; }
  .pf-justify-between { justify-content: space-between; }
  .pf-justify-end { justify-content: flex-end; }
  .pf-grow { flex: 1 1 auto; }
  .pf-shrink-0 { flex: none; }
  
  /* Text */
  .pf-text-start { text-align: start; }
  .pf-text-center { text-align: center; }
  .pf-text-end { text-align: end; }
  .pf-text-xs { font-size: var(--pf-text-xs); }
  .pf-text-sm { font-size: var(--pf-text-sm); }
  .pf-text-lg { font-size: var(--pf-text-lg); }
  .pf-text-xl { font-size: var(--pf-text-xl); }
  /* The display steps had tokens but no utilities, so a heading that needed one
     had to reach for an inline style — which the CSP forbids. */
  .pf-text-2xl { font-size: var(--pf-text-2xl); }
  .pf-text-3xl { font-size: var(--pf-text-3xl); }
  .pf-text-4xl { font-size: var(--pf-text-4xl); }
  .pf-text-5xl { font-size: var(--pf-text-5xl); }
  .pf-display { font-family: var(--pf-font-display); letter-spacing: -0.02em; }
  .pf-mono { font-family: var(--pf-font-mono); }
  .pf-weight-500 { font-weight: 500; }
  .pf-weight-600 { font-weight: 600; }
  .pf-weight-700 { font-weight: 700; }
  .pf-balance { text-wrap: balance; }
  .pf-measure { max-width: var(--pf-measure); }
  .pf-measure-none { max-width: none; }
  
  /* Colour */
  .pf-fg-accent { color: var(--pf-accent); }
  .pf-fg-accent-2 { color: var(--pf-accent-2); }
  .pf-fg-paper { color: var(--pf-base-50); }
  .pf-fg-muted { color: var(--pf-text-muted); }
  .pf-bg-deep { background: var(--pf-base-900); }
  .pf-bg-base { background: var(--pf-base-800); }
  .pf-bg-surface { background: var(--pf-surface); }
  .pf-bg-accent-wash { background: var(--pf-hue-1-wash); }
  .pf-bg-accent-2-wash { background: var(--pf-hue-2-wash); }
  .pf-bg-mesh { background-image: var(--pf-mesh); }
  
  /* Sticky offsets, for sidebars and toolbars. --top-lg clears a sticky nav. */
  .pf-sticky { position: sticky; align-self: start; }
  .pf-sticky-top { top: 2rem; }
  .pf-sticky-nav { top: 6rem; }
  
  /* Shape */
  .pf-round { border-radius: var(--pf-radius); }
  .pf-round-lg { border-radius: var(--pf-radius-lg); }
  .pf-round-pill { border-radius: var(--pf-radius-pill); }
  .pf-bordered { border: 1px solid var(--pf-border); }
  .pf-bordered-accent { border: 1px solid var(--pf-border-strong); }
  .pf-lift { box-shadow: var(--pf-lift); }
  .pf-overflow-hidden { overflow: hidden; }
  
  
  /* ==========================================================================
     #SIZING, POSITION AND LAYERS
     ========================================================================== */
  
  /**
   * The helpers a layout reaches for once and would otherwise get a one-off
   * rule: widths as fractions of the container, a few heights, position and
   * z-index, overflow, object-fit and aspect-ratio.
   */
  .pf-w-full { width: 100%; }
  .pf-w-auto { width: auto; }
  .pf-w-half { width: 50%; }
  .pf-w-min { width: min-content; }
  .pf-w-max { width: max-content; }
  .pf-w-fit { width: fit-content; }
  .pf-max-w-none { max-width: none; }
  .pf-max-w-xs { max-width: 20rem; }
  .pf-max-w-sm { max-width: 24rem; }
  .pf-max-w-md { max-width: 32rem; }
  .pf-max-w-lg { max-width: 42rem; }
  .pf-max-w-xl { max-width: 56rem; }
  
  .pf-h-full { height: 100%; }
  .pf-h-screen { height: 100vh; height: 100dvh; }
  .pf-min-h-0 { min-height: 0; }
  .pf-min-w-0 { min-width: 0; }
  
  .pf-relative { position: relative; }
  .pf-absolute { position: absolute; }
  .pf-fixed { position: fixed; }
  .pf-static { position: static; }
  .pf-inset-0 { inset: 0; }
  .pf-top-0 { top: 0; }
  .pf-right-0 { inset-inline-end: 0; }
  .pf-bottom-0 { bottom: 0; }
  .pf-left-0 { inset-inline-start: 0; }
  
  .pf-z-0 { z-index: 0; }
  .pf-z-10 { z-index: 10; }
  .pf-z-20 { z-index: 20; }
  .pf-z-40 { z-index: 40; }
  .pf-z-60 { z-index: 60; }
  
  .pf-overflow-auto { overflow: auto; }
  .pf-overflow-x-auto { overflow-x: auto; }
  .pf-overflow-visible { overflow: visible; }
  
  .pf-object-cover { object-fit: cover; }
  .pf-object-contain { object-fit: contain; }
  .pf-aspect-square { aspect-ratio: 1 / 1; }
  .pf-aspect-video { aspect-ratio: 16 / 9; }
  
  /* ==========================================================================
     #TYPOGRAPHY HELPERS
     ========================================================================== */
  
  .pf-uppercase { text-transform: uppercase; letter-spacing: 0.06em; }
  .pf-capitalize { text-transform: capitalize; }
  .pf-normal-case { text-transform: none; }
  .pf-underline { text-decoration: underline; text-underline-offset: 0.22em; }
  .pf-no-underline { text-decoration: none; }
  .pf-italic { font-style: italic; }
  .pf-tabular { font-variant-numeric: tabular-nums; }
  .pf-leading-tight { line-height: var(--pf-leading-tight); }
  .pf-leading-snug { line-height: var(--pf-leading-snug); }
  .pf-leading-normal { line-height: var(--pf-leading); }
  .pf-truncate { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  
  /**
   * Line clamp. -webkit-box is still the interoperable way to do this; the
   * standard `line-clamp` is listed first so browsers that support it use it.
   */
  .pf-clamp-2,
  .pf-clamp-3 { display: -webkit-box; -webkit-box-orient: vertical; overflow: hidden; }
  .pf-clamp-2 { line-clamp: 2; -webkit-line-clamp: 2; }
  .pf-clamp-3 { line-clamp: 3; -webkit-line-clamp: 3; }
  
  /* ==========================================================================
     #BORDERS, OPACITY, CURSOR
     ========================================================================== */
  
  .pf-border-0 { border: 0; }
  .pf-border-t { border-top: 1px solid var(--pf-border); }
  .pf-border-b { border-bottom: 1px solid var(--pf-border); }
  .pf-round-none { border-radius: 0; }
  .pf-round-sm { border-radius: var(--pf-radius-sm); }
  .pf-circle { border-radius: 50%; }
  
  .pf-opacity-50 { opacity: 0.5; }
  .pf-opacity-75 { opacity: 0.75; }
  .pf-cursor-pointer { cursor: pointer; }
  .pf-select-none { user-select: none; }
  .pf-pointer-none { pointer-events: none; }
  
  /* ==========================================================================
     #DEPTH, MOTION AND TRANSFORMS
     ========================================================================== */
  
  .pf-shadow-sm { box-shadow: var(--pf-shadow-sm); }
  .pf-shadow { box-shadow: var(--pf-shadow); }
  .pf-shadow-lg { box-shadow: var(--pf-lift); }
  .pf-shadow-none { box-shadow: none; }
  .pf-ring { box-shadow: var(--pf-ring); }
  
  .pf-transition { transition: all var(--pf-speed) var(--pf-ease); }
  .pf-transition-colors {
    transition: background-color var(--pf-speed) var(--pf-ease),
      border-color var(--pf-speed) var(--pf-ease), color var(--pf-speed) var(--pf-ease);
  }
  
  /**
   * Hover affordances. Each pairs a transform with a transition and is scoped
   * to (hover: hover), so a touch device does not get a state it can only enter
   * by pressing and holding.
   */
  @media (hover: hover) {
    .pf-hover-lift { transition: transform var(--pf-speed) var(--pf-ease), box-shadow var(--pf-speed) var(--pf-ease); }
    .pf-hover-lift:hover { transform: translateY(-2px); box-shadow: var(--pf-shadow); }
    .pf-hover-border { transition: border-color var(--pf-speed) var(--pf-ease); }
    .pf-hover-border:hover { border-color: var(--pf-border-strong); }
    .pf-hover-bright { transition: opacity var(--pf-speed) var(--pf-ease); }
    .pf-hover-bright:hover { opacity: 1; }
  }
  
  /* ==========================================================================
     #DIVIDE AND RULES
     ========================================================================== */
  
  /**
   * A border between children rather than around them. Saves the
   * :last-child override that every hand-written list rule ends up needing.
   */
  .pf-divide-y > * + * { border-top: 1px solid var(--pf-border); }
  .pf-divide-x > * + * { border-inline-start: 1px solid var(--pf-border); }
  .pf-vr {
    width: 1px;
    align-self: stretch;
    min-height: 1.5em;
    background: var(--pf-border);
    flex: none;
  }
  
  /* ==========================================================================
     #CONTAINER QUERIES
     ========================================================================== */
  
  /**
   * A component in a narrow sidebar and the same component in a wide main
   * column are the same width problem, and a viewport media query cannot tell
   * them apart. Container queries can.
   *
   *   <div class="pf-container-q">
   *     <article class="pf-card pf-cq-row"> ... </article>
   *   </div>
   *
   * .pf-cq-row lays the card out horizontally once ITS OWN container is at
   * least 30rem wide, wherever that container sits on the page. This is the
   * piece that makes a modular framework genuinely reusable: a component stops
   * needing to know where it was dropped.
   *
   * Support is Chrome 105, Safari 16, Firefox 110 and up. Older engines keep
   * the stacked layout, which is the correct fallback rather than a broken one.
   */
  .pf-container-q { container-type: inline-size; }
  
  @container (min-width: 30rem) {
    .pf-cq-row { flex-direction: row; align-items: center; }
    .pf-cq-2 { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); }
    .pf-cq-side { display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: center; }
    .pf-cq-show { display: initial; }
    .pf-cq-hide { display: none; }
  }
  @container (min-width: 48rem) {
    .pf-cq-3 { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); }
    .pf-cq-4 { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); }
  }
  
  /* ==========================================================================
     #RESPONSIVE VARIANTS
     ========================================================================== */
  
  /**
   * Mobile first, Bootstrap-style infixes rather than Tailwind's escaped colon:
   * .pf-md-hidden applies from 768px up, .pf-hidden applies everywhere.
   *
   *   sm 576px   md 768px   lg 992px   xl 1200px
   *
   * Only the properties that genuinely change per breakpoint are generated -
   * display, direction, alignment, text alignment, width and order. Generating
   * the whole utility set at five breakpoints is how a stylesheet reaches
   * 300 KB, and a build step becomes mandatory to trim it again.
   */@media (min-width: 576px) {
    .pf-sm-hidden { display: none; }
    .pf-sm-block { display: block; }
    .pf-sm-flex { display: flex; }
    .pf-sm-grid-d { display: grid; }
    .pf-sm-inline-flex { display: inline-flex; }
    .pf-sm-flex-col { flex-direction: column; }
    .pf-sm-flex-row { flex-direction: row; }
    .pf-sm-text-left { text-align: start; }
    .pf-sm-text-center { text-align: center; }
    .pf-sm-text-right { text-align: end; }
    .pf-sm-items-center { align-items: center; }
    .pf-sm-items-start { align-items: flex-start; }
    .pf-sm-justify-between { justify-content: space-between; }
    .pf-sm-justify-center { justify-content: center; }
    .pf-sm-w-full { width: 100%; }
    .pf-sm-w-auto { width: auto; }
    .pf-sm-order-first { order: -1; }
    .pf-sm-order-last { order: 99; }
    .pf-sm-span-full { grid-column: 1 / -1; }
  }
  @media (min-width: 768px) {
    .pf-md-hidden { display: none; }
    .pf-md-block { display: block; }
    .pf-md-flex { display: flex; }
    .pf-md-grid-d { display: grid; }
    .pf-md-inline-flex { display: inline-flex; }
    .pf-md-flex-col { flex-direction: column; }
    .pf-md-flex-row { flex-direction: row; }
    .pf-md-text-left { text-align: start; }
    .pf-md-text-center { text-align: center; }
    .pf-md-text-right { text-align: end; }
    .pf-md-items-center { align-items: center; }
    .pf-md-items-start { align-items: flex-start; }
    .pf-md-justify-between { justify-content: space-between; }
    .pf-md-justify-center { justify-content: center; }
    .pf-md-w-full { width: 100%; }
    .pf-md-w-auto { width: auto; }
    .pf-md-order-first { order: -1; }
    .pf-md-order-last { order: 99; }
    .pf-md-span-full { grid-column: 1 / -1; }
  }
  @media (min-width: 992px) {
    .pf-lg-hidden { display: none; }
    .pf-lg-block { display: block; }
    .pf-lg-flex { display: flex; }
    .pf-lg-grid-d { display: grid; }
    .pf-lg-inline-flex { display: inline-flex; }
    .pf-lg-flex-col { flex-direction: column; }
    .pf-lg-flex-row { flex-direction: row; }
    .pf-lg-text-left { text-align: start; }
    .pf-lg-text-center { text-align: center; }
    .pf-lg-text-right { text-align: end; }
    .pf-lg-items-center { align-items: center; }
    .pf-lg-items-start { align-items: flex-start; }
    .pf-lg-justify-between { justify-content: space-between; }
    .pf-lg-justify-center { justify-content: center; }
    .pf-lg-w-full { width: 100%; }
    .pf-lg-w-auto { width: auto; }
    .pf-lg-order-first { order: -1; }
    .pf-lg-order-last { order: 99; }
    .pf-lg-span-full { grid-column: 1 / -1; }
  }
  @media (min-width: 1200px) {
    .pf-xl-hidden { display: none; }
    .pf-xl-block { display: block; }
    .pf-xl-flex { display: flex; }
    .pf-xl-grid-d { display: grid; }
    .pf-xl-inline-flex { display: inline-flex; }
    .pf-xl-flex-col { flex-direction: column; }
    .pf-xl-flex-row { flex-direction: row; }
    .pf-xl-text-left { text-align: start; }
    .pf-xl-text-center { text-align: center; }
    .pf-xl-text-right { text-align: end; }
    .pf-xl-items-center { align-items: center; }
    .pf-xl-items-start { align-items: flex-start; }
    .pf-xl-justify-between { justify-content: space-between; }
    .pf-xl-justify-center { justify-content: center; }
    .pf-xl-w-full { width: 100%; }
    .pf-xl-w-auto { width: auto; }
    .pf-xl-order-first { order: -1; }
    .pf-xl-order-last { order: 99; }
    .pf-xl-span-full { grid-column: 1 / -1; }
  }
  
  /* ==========================================================================
     #SCROLL REVEAL
     ========================================================================== */
  
  /**
   * .pf-reveal / .pf-reveal-soft
   *
   * Content comes into focus as it enters the viewport, using scroll-driven
   * animations - no script, no IntersectionObserver, nothing to initialise.
   *
   * Two guards, both load-bearing:
   *
   *   @supports (animation-timeline: view())  keeps the animation out of
   *   engines that would apply the keyframes without ever advancing them,
   *   which would leave the element stuck at opacity 0 forever.
   *
   *   prefers-reduced-motion: no-preference  means motion is opt-in from the
   *   user's settings rather than opt-out.
   *
   * The un-animated state is the visible one. That ordering is the whole safety
   * argument: every failure mode ends with the content on screen.
   */
  @supports (animation-timeline: view()) {
    @media (prefers-reduced-motion: no-preference) {
      .pf-reveal {
        animation: pf-reveal-in linear both;
        animation-timeline: view();
        animation-range: entry 5% cover 26%;
      }
      .pf-reveal-soft {
        animation: pf-fade-in linear both;
        animation-timeline: view();
        animation-range: entry 0% cover 22%;
      }
    }
  }
  @keyframes pf-reveal-in {
    from { opacity: 0; transform: translateY(1.75rem); }
    to   { opacity: 1; transform: none; }
  }
  @keyframes pf-fade-in {
    from { opacity: 0; }
    to   { opacity: 1; }
  }
  
  /* Responsive visibility */
  @media (max-width: 860px) {
    .pf-hide-sm { display: none !important; }
  }
  @media (min-width: 861px) {
    .pf-hide-lg { display: none !important; }
  }
  /* ========================================================================
     PRINT
     ========================================================================
     A printed page is a different medium, not a screenshot of a screen. Dark
     backgrounds waste ink and render grey; navigation is dead weight; a link
     that says "read more" is useless on paper because the address is gone.

     This block is written for the case a documentation or article page is
     actually printed or saved as a PDF, which for a publication is a real
     thing readers do.
     ======================================================================== */

  /* Hidden on screen, shown on paper. The counterpart lives in the print
     block below. */
  .pf-print-only { display: none; }

  @media print {
    /* Force the light palette. A printer given a dark background either
       floods the page or drops it, and neither is readable. */
    :root {
      --pf-bg: #ffffff;
      --pf-bg-deep: #ffffff;
      --pf-surface: transparent;
      --pf-surface-raised: transparent;
      --pf-text: #000000;
      --pf-text-muted: #333333;
      --pf-accent: #000000;
      --pf-accent-2: #000000;
      --pf-border: #999999;
      --pf-border-strong: #666666;
      --pf-mesh: none;
      --pf-cut: 0px;
    }

    *,
    *::before,
    *::after {
      background: transparent !important;
      box-shadow: none !important;
      color: #000 !important;
      text-shadow: none !important;
    }

    body { font-size: 11pt; line-height: 1.45; }

    /* Chrome that means nothing on paper. */
    .pf-nav,
    .pf-topbar,
    .pf-footer,
    .pf-cta,
    .pf-skip,
    .pf-totop,
    .pf-sidenav,
    .pf-bottombar,
    .pf-drawer,
    .pf-pagination,
    .pf-tabs__label,
    .pf-scroller,
    .pf-breadcrumb,
    [data-pf-theme-toggle],
    .pf-code__copy { display: none !important; }

    /* Tabs and accordions hide content behind a control that cannot be
       clicked on paper, so print every panel. */
    .pf-tabs__panel { display: block !important; }
    .pf-accordion details { display: block !important; }
    .pf-accordion summary { font-weight: 600; }

    /* The address is the useful part of a link once the page is paper. */
    .pf-prose a[href^="http"]::after,
    main a[href^="http"]::after { content: " (" attr(href) ")"; font-size: 0.85em; word-break: break-all; }
    a[href^="#"]::after,
    .pf-btn[href]::after { content: none; }

    /* Structure that survives without colour. */
    .pf-card,
    .pf-plan,
    .pf-alert,
    .pf-code,
    .pf-table-wrap { border: 1px solid #999 !important; }

    .pf-alert__title { font-weight: 700; }
    .pf-code pre { white-space: pre-wrap; word-break: break-word; }

    /* Page breaks. A heading stranded at the foot of a page and a table split
       across two are the two things that make a printed reference unusable. */
    h1, h2, h3, h4 { break-after: avoid-page; page-break-after: avoid; }
    figure, table, .pf-card, .pf-alert, .pf-code, blockquote { break-inside: avoid; page-break-inside: avoid; }
    .pf-section { break-before: auto; padding-block: 0.6cm 0; }
    thead { display: table-header-group; }
    tr { break-inside: avoid; }

    /* Give the sheet its own margins rather than the browser's default. */
    @page { margin: 1.6cm 1.4cm; }

    .pf-container,
    .pf-container--wide,
    .pf-container--narrow { max-width: none; padding-inline: 0; }

    .pf-hero { padding-block: 0 0.6cm; }
    .pf-grid, .pf-split, .pf-shell { display: block; }
    .pf-grid > * + *, .pf-split > * + * { margin-block-start: 0.5cm; }

    /* The print-only helper pair, for a note or a URL that belongs on paper
       and nowhere else. */
    .pf-print-only { display: revert !important; }
    .pf-no-print { display: none !important; }
  }
}
