/* ============================================================
   Penguinstones — Laravel rebuild. FAITHFUL port of the live theme's
   design: real self-hosted fonts, real tokens, real header/hero/sections.
   Foundation + shared chrome + home. Page-specific CSS lives in each
   Blade view's @push('head') block.
   ============================================================ */

/* ---- Self-hosted fonts (copied from the theme /fonts) ---- */
@font-face{font-family:'Lilita One';font-style:normal;font-weight:400;font-display:swap;
  src:url('/fonts/lilita-one-latin.woff2') format('woff2');
  unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+2000-206F,U+2074,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD;}
@font-face{font-family:'Lilita One';font-style:normal;font-weight:400;font-display:swap;
  src:url('/fonts/lilita-one-latin-ext.woff2') format('woff2');
  unicode-range:U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF;}
@font-face{font-family:'IBM Plex Mono';font-style:normal;font-weight:400;font-display:swap;src:url('/fonts/ibm-plex-mono-400-latin.woff2') format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+2000-206F,U+20AC,U+2122,U+2212,U+FEFF,U+FFFD;}
@font-face{font-family:'IBM Plex Mono';font-style:normal;font-weight:400;font-display:swap;src:url('/fonts/ibm-plex-mono-400-latin-ext.woff2') format('woff2');unicode-range:U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+2113,U+2C60-2C7F,U+A720-A7FF;}
@font-face{font-family:'IBM Plex Mono';font-style:normal;font-weight:500;font-display:swap;src:url('/fonts/ibm-plex-mono-500-latin.woff2') format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+2000-206F,U+20AC,U+2122,U+2212,U+FEFF,U+FFFD;}
@font-face{font-family:'IBM Plex Mono';font-style:normal;font-weight:500;font-display:swap;src:url('/fonts/ibm-plex-mono-500-latin-ext.woff2') format('woff2');unicode-range:U+0100-02BA,U+1E00-1E9F,U+2C60-2C7F,U+A720-A7FF;}
@font-face{font-family:'IBM Plex Mono';font-style:normal;font-weight:600;font-display:swap;src:url('/fonts/ibm-plex-mono-600-latin.woff2') format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+2000-206F,U+20AC,U+2122,U+2212,U+FEFF,U+FFFD;}
@font-face{font-family:'IBM Plex Mono';font-style:normal;font-weight:600;font-display:swap;src:url('/fonts/ibm-plex-mono-600-latin-ext.woff2') format('woff2');unicode-range:U+0100-02BA,U+1E00-1E9F,U+2C60-2C7F,U+A720-A7FF;}
@font-face{font-family:'IBM Plex Mono';font-style:normal;font-weight:700;font-display:swap;src:url('/fonts/ibm-plex-mono-700-latin.woff2') format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+2000-206F,U+20AC,U+2122,U+2212,U+FEFF,U+FFFD;}
@font-face{font-family:'IBM Plex Mono';font-style:normal;font-weight:700;font-display:swap;src:url('/fonts/ibm-plex-mono-700-latin-ext.woff2') format('woff2');unicode-range:U+0100-02BA,U+1E00-1E9F,U+2C60-2C7F,U+A720-A7FF;}

/* ---- Real design tokens ---- */
:root{
  --ps-navy:#0f172a; --ps-navy-mid:#1e3a5f; --ps-blue:#2563eb; --ps-blue-light:#60a5fa;
  --ps-white:#ffffff; --ps-bg:#f8faff; --ps-border:#e2e8f0; --ps-text:#1e293b;
  --ps-muted:#64748b;
  --ps-yellow:#F7C32C; --ps-yellow-hover:#D9A815; --ps-yellow-ink:#ffffff;
  --ps-teal:#37959B; --ps-purple:#9381AA;
  --ps-font:'IBM Plex Mono',ui-monospace,Menlo,monospace;
  --ps-font-heading:'Lilita One','Arial Black',system-ui,sans-serif;
  /* READING text (stone stories, FAQ, legal, form help). Mono stays for what it
     is good at — numbers, labels, badges, nav — but 14px monospace paragraphs
     read like a terminal. A humanist sans, self-hosted-free: the system stack
     (SF Pro on Apple, Segoe on Windows, Roboto on Android) costs zero bytes and
     zero GDPR review. To switch to a webfont later (Space Grotesk was the
     nominated one): add its @font-face + woff2 in /fonts and change THIS token. */
  --ps-font-prose:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans",sans-serif;
  --ps-content:min(1600px,92vw);
  --ps-shadow-sm:0 4px 14px rgba(15,23,42,.06);
  --ps-shadow-md:0 12px 30px rgba(15,23,42,.10);
  --ps-radius:14px;
  /* SEMANTIC surface/text tokens — the dark theme swaps THESE and only these.
     --ps-navy stays navy in both themes because it is also a BACKGROUND (CTA
     cards, cluster discs, buttons); text that used to be navy is --ps-heading. */
  --ps-surface:#ffffff;        /* cards, panels, inputs */
  --ps-surface-2:#f8faff;      /* nested panels, table heads, hover rows */
  --ps-heading:#0f172a;        /* headings + strong text on light surfaces */
  --ps-text-soft:#475569;      /* long-form legal prose */
  --ps-input-bg:#ffffff;
  --ps-link:#2563eb;
  --ps-tile-filter:saturate(.8) contrast(.98);   /* OSM tiles */
  --ps-tint-yellow-bg:linear-gradient(135deg,#FFFBEF 0%,#FFF6DC 100%);
  --ps-tint-yellow-border:#F2DFA4;
  --ps-tint-green-bg:#DCEFD8;
  --ps-tint-green-text:#2F6B33;
  --ps-tint-green-border:#BFE3B8;
  --ps-tint-gold:#fff8e1;
  --ps-row-hover:#eff6ff;
  /* CHROME — header, footer, mobile menu, bottom tab bar.
     These were hardcoded #000 + rgba(255,255,255,…) so the theme toggle repainted
     the PAGE and left the frame around it black in both themes. The owner's words:
     "should truly change also footer and headers everywhere, not just the body".
     ⚠️ THE ACCENT IS NOT THE BRAND YELLOW ON LIGHT, and that is a contrast
     requirement rather than a preference: #F7C32C on white is 1.8:1, which fails
     WCAG AA (4.5:1) for text by a wide margin — an active tab or a hovered nav
     link in yellow-on-white is close to invisible. Yellow stays where it still
     works, on FILLS (the Add-to-map button, the raised + circle), where the ink
     sits on the yellow rather than the yellow on the ground. Navigation STATE is
     carried by blue on light and by yellow on dark, both ≥6:1. */
  --ps-chrome-bg:#ffffff;
  --ps-chrome-panel:#f8fafc;      /* burger sheet — reads as a panel over the bar */
  --ps-chrome-text:#0f172a;
  --ps-chrome-muted:#5a6a85;
  --ps-chrome-border:#e2e8f0;     /* hairline under the header / over the footer */
  --ps-chrome-line:#cbd5e1;       /* outlines on chrome controls */
  --ps-chrome-hover:#eef2f9;
  --ps-chrome-accent:#1d4ed8;
  --ps-chrome-accent-ink:#ffffff;   /* ink ON an accent fill — must flip with the accent */
  /* EMPHASIS ON CONTENT SURFACES (eyebrows, counts, card titles). Same reason
     the chrome accent is not yellow: #F7C32C on white is 1.8:1 against AA's
     4.5:1, so an 11px uppercase eyebrow in brand yellow is unreadable the
     moment the surface under it turns light. Yellow stays on FILLS. */
  --ps-accent:#1d4ed8;
  /* THE SELECTED-CHOICE PAIR — a chosen tile and the ink on it.
     ⚠️ THE TWO THEMES WANT OPPOSITE ANSWERS, which is why this is a token and
     not a colour. A selected option has to be the HIGHEST-CONTRAST surface
     against the card it sits on: navy on a white card, white on a dark one.
     Navy in both was shipped for one commit and was invisible in the dark
     theme — the chosen tile measured rgb(15,23,42) against a rgb(18,27,46)
     card, a difference of four points per channel, so nothing on the form
     showed which mode was selected. */
  --ps-select-bg:#0f172a;
  --ps-select-ink:#ffffff;
  /* ⚠️ THE SAME IN BOTH PALETTES, ON PURPOSE — the one token here that does not
     flip. The selected segment of a view toggle has to be the LIGHTEST thing in
     its control, and the track is light-grey on one theme and near-black on the
     other, so white works against both. Declared as a token rather than written
     as a literal so the intent is visible beside the flipping ones, and so the
     "no hardcoded white surface" guard in ThemeTest keeps its teeth. */
  --ps-segment-bg:#ffffff;
  --ps-segment-ink:#0f172a;
  /* REQUIRED-FIELD MARKS. Red in both themes by decision — but not the SAME red:
     #c62828 on the dark card measures 3.1:1, under the 4.5:1 floor for 13px
     text, so the dark theme takes a lighter one at 5.9:1. A red nobody can read
     is not a warning. */
  --ps-required:#c62828;
  /* The empty half of a progress bar. Deliberately NOT --ps-surface-2, which is
     #f8faff — a faint blue that reads as a second colour beside the yellow. */
  --ps-progress-track:#e4e7ec;
  /* ⚠️ THE FILL IS BLUE ON LIGHT AND YELLOW ON DARK (owner, 2026-08-19), and
     this token is the whole mechanism — do not hard-code a colour on
     .ss-progress-fill. Yellow on white is the site's weakest contrast pairing
     (#F7C32C on #fff is 1.7:1), so a thin 9px bar of it reads as barely there;
     on the dark ground yellow is the brand colour doing what it is good at.
     An earlier round made it yellow in both, which was my misreading of the
     owner describing what he wanted as if it were a complaint. */
  --ps-progress-fill:#2563eb;
  /* THE GOAL BAND. One token set rather than three copies of the `.ph-goal`
     selector, so the artwork, the ground it sits on and the number over it can
     never be set from different themes. The light artwork is not a naive invert of the
     dark one — a straight invert gives a pure-white ground brighter than any
     surface on the site, which reads as a pasted rectangle; it is remapped onto
     the light palette so the map sits IN the band rather than on it. */
  --ph-goal-map:url('/images/goal-bg-worldmap-light.webp');
  --ph-goal-ground:#eef2f9;
  /* ⚠️ ITS OWN TOKEN RATHER THAN --ps-accent, because the two themes genuinely
     want different answers and neither shared token gives both. Navy on light
     (owner's call: the blue accent was too loud for a number that never
     changes), brand yellow on dark, where yellow is both readable and the
     iconic look. --ps-heading would have handed dark mode a near-white number;
     --ps-accent hands light mode a shouting blue one. */
  --ph-goal-number:#0f172a;
  /* ⚠️ THE FOOTPRINTS ARE PURE WHITE ARTWORK ON TRANSPARENCY (measured: the
     only opaque colour in penguin-feet-240.webp is #ffffff). Correct on the
     navy band, invisible the moment the band turns light — a regression the
     light theme introduced rather than one it inherited. brightness(0) flattens
     the white to black and the opacity softens it to roughly the weight of the
     map's landmasses, so it reads as a faint trail instead of a hole. A second
     artwork file would need generating, versioning and deploying to say the
     same thing. */
  --ph-goal-feet-filter:brightness(0) opacity(.16);
  --ps-chrome-field:#f1f5f9;
  --ps-chrome-link:#2563eb;
  --ps-chrome-shadow:0 1px 0 rgba(15,23,42,.04);
  color-scheme:light;
}
/* ── DARK THEME ─────────────────────────────────────────────────────────────
   Two triggers, one palette: an explicit choice stamps data-theme on <html>
   (js in the layout head, before first paint — no flash), and with NO choice
   the OS setting decides. `:root:not([data-theme="light"])` inside the media
   query is what lets an explicit "light" beat a dark OS. Header, footer and
   the black bands are already black and stay; only surfaces and text swap. */
:root[data-theme="dark"]{
  --ps-bg:#0b1220; --ps-surface:#121b2e; --ps-surface-2:#0f172a; --ps-border:#26324a;
  --ps-text:#e2e8f0; --ps-muted:#94a3b8; --ps-heading:#f1f5f9; --ps-text-soft:#cbd5e1;
  --ps-input-bg:#0f172a; --ps-link:#7db4ff; --ps-blue-light:#8ec2ff;
  --ps-shadow-sm:0 4px 14px rgba(0,0,0,.35); --ps-shadow-md:0 12px 30px rgba(0,0,0,.5);
  --ps-tile-filter:invert(1) hue-rotate(180deg) brightness(.82) contrast(.92) saturate(.55);
  --ps-tint-yellow-bg:linear-gradient(135deg,rgba(247,195,44,.10),rgba(247,195,44,.06));
  --ps-tint-yellow-border:rgba(247,195,44,.32);
  --ps-tint-green-bg:rgba(34,197,94,.14); --ps-tint-green-text:#86efac; --ps-tint-green-border:rgba(34,197,94,.35);
  --ps-tint-gold:rgba(212,160,23,.14); --ps-row-hover:#182338;
  --ps-chrome-bg:#000000; --ps-chrome-panel:#0f172a; --ps-chrome-text:#ffffff;
  --ps-chrome-muted:rgba(255,255,255,.68); --ps-chrome-border:rgba(255,255,255,.08);
  --ps-chrome-line:rgba(255,255,255,.18); --ps-chrome-hover:rgba(255,255,255,.06);
  --ps-chrome-accent:#F7C32C; --ps-chrome-accent-ink:#111111; --ps-accent:#F7C32C; --ps-chrome-field:rgba(255,255,255,.08);
  --ps-chrome-link:#60a5fa; --ps-chrome-shadow:none;
  --ph-goal-map:url('/images/goal-bg-worldmap.webp'); --ph-goal-ground:#0b1530;
  --ph-goal-number:#F7C32C; --ph-goal-feet-filter:none;
  --ps-select-bg:#ffffff; --ps-select-ink:#0f172a;
  --ps-segment-bg:#ffffff; --ps-segment-ink:#0f172a; --ps-required:#ff8a80; --ps-progress-track:#2a3550; --ps-progress-fill:#F7C32C;
  color-scheme:dark;
}
@media (prefers-color-scheme: dark){
  :root:not([data-theme="light"]){
    --ps-bg:#0b1220; --ps-surface:#121b2e; --ps-surface-2:#0f172a; --ps-border:#26324a;
    --ps-text:#e2e8f0; --ps-muted:#94a3b8; --ps-heading:#f1f5f9; --ps-text-soft:#cbd5e1;
    --ps-input-bg:#0f172a; --ps-link:#7db4ff; --ps-blue-light:#8ec2ff;
    --ps-shadow-sm:0 4px 14px rgba(0,0,0,.35); --ps-shadow-md:0 12px 30px rgba(0,0,0,.5);
    --ps-tile-filter:invert(1) hue-rotate(180deg) brightness(.82) contrast(.92) saturate(.55);
    --ps-tint-yellow-bg:linear-gradient(135deg,rgba(247,195,44,.10),rgba(247,195,44,.06));
    --ps-tint-yellow-border:rgba(247,195,44,.32);
    --ps-tint-green-bg:rgba(34,197,94,.14); --ps-tint-green-text:#86efac; --ps-tint-green-border:rgba(34,197,94,.35);
    --ps-tint-gold:rgba(212,160,23,.14); --ps-row-hover:#182338;
    --ps-chrome-bg:#000000; --ps-chrome-panel:#0f172a; --ps-chrome-text:#ffffff;
    --ps-chrome-muted:rgba(255,255,255,.68); --ps-chrome-border:rgba(255,255,255,.08);
    --ps-chrome-line:rgba(255,255,255,.18); --ps-chrome-hover:rgba(255,255,255,.06);
    --ps-chrome-accent:#F7C32C; --ps-chrome-accent-ink:#111111; --ps-accent:#F7C32C; --ps-chrome-field:rgba(255,255,255,.08);
    --ps-chrome-link:#60a5fa; --ps-chrome-shadow:none;
    --ph-goal-map:url('/images/goal-bg-worldmap.webp'); --ph-goal-ground:#0b1530;
    --ph-goal-number:#F7C32C; --ph-goal-feet-filter:none;
    --ps-select-bg:#ffffff; --ps-select-ink:#0f172a;
    --ps-segment-bg:#ffffff; --ps-segment-ink:#0f172a; --ps-required:#ff8a80; --ps-progress-track:#2a3550; --ps-progress-fill:#F7C32C;
    color-scheme:dark;
  }
}
/* OSM tiles follow the theme (map page + the stone mini-map). Marker pane untouched. */
.leaflet-tile-pane{filter:var(--ps-tile-filter)}
/* Brand cluster discs — the map page (map.js iconCreateFunction + server cells)
   and the contributor profile map share them: navy disc, yellow ring. */
.ps-cluster{background:transparent !important}
.ps-cluster div{width:100%;height:100%;border-radius:50%;background:var(--ps-navy);
  border:3px solid var(--ps-yellow);box-shadow:0 0 0 6px rgba(247,195,44,.22),0 8px 20px rgba(15,23,42,.35);
  display:flex;align-items:center;justify-content:center;color:#fff;
  font-family:var(--ps-font-heading);letter-spacing:.02em;transition:transform .15s,box-shadow .15s}
.ps-cluster--sm div{font-size:15px}
.ps-cluster--md div{font-size:17px}
.ps-cluster--lg div{font-size:19px;background:#0b1530}
.ps-cluster:hover div{transform:scale(1.06);box-shadow:0 0 0 8px rgba(247,195,44,.3),0 10px 24px rgba(15,23,42,.4)}

/* ── PINS AND CLUSTERS IN THE DARK THEME ─────────────────────────────────────
   ⚠️ THE TILE FILTER DARKENS THE MAP BUT NOT WHAT SITS ON IT. --ps-tile-filter
   inverts the tile pane only (that scoping is deliberate — it must never touch
   the markers, or the penguins come out as photographic negatives). The result
   is that the standard pin, whose teardrop is #1A1A1A on a #000 stroke, ends up
   near-black on a near-black map: you cannot see where it points.

   ⚠️ A WHITE OUTLINE, NOT AN INVERT. Inverting the marker would turn the
   penguin's white belly black and its black body white — the brand mark,
   backwards. Two tight drop-shadows draw a rim around whatever the artwork
   already is, so all three pin types (black, golden, purple) lift off the dark
   map with their own colours intact.

   Kept off the light theme entirely: the pins read fine on light tiles, and a
   white rim there would just look like a printing error. */
:root[data-theme="dark"] .penguin-marker,
:root[data-theme="dark"] .ps-cluster div{
  filter:drop-shadow(0 0 1px rgba(255,255,255,.95)) drop-shadow(0 0 3px rgba(255,255,255,.55));
}
/* The cluster disc is navy on a dark map for the same reason — the yellow ring
   carries it, but the disc itself needs to separate from the ground. */
:root[data-theme="dark"] .ps-cluster div{background:#1e3a5f}
:root[data-theme="dark"] .ps-cluster--lg div{background:#16304f}
@media (prefers-color-scheme: dark){
  :root:not([data-theme="light"]) .penguin-marker,
  :root:not([data-theme="light"]) .ps-cluster div{
    filter:drop-shadow(0 0 1px rgba(255,255,255,.95)) drop-shadow(0 0 3px rgba(255,255,255,.55));
  }
  :root:not([data-theme="light"]) .ps-cluster div{background:#1e3a5f}
  :root:not([data-theme="light"]) .ps-cluster--lg div{background:#16304f}
}
/* Motion: every hover lift / fade in this stylesheet respects the OS setting. */
@media (prefers-reduced-motion: reduce){
  *,*::before,*::after{animation-duration:.01ms !important;animation-iteration-count:1 !important;transition-duration:.01ms !important;scroll-behavior:auto !important}
}
/* One focus ring for the whole site — visible, on-brand, never on mouse click. */
:focus-visible{outline:3px solid var(--ps-yellow);outline-offset:2px;border-radius:4px}
.ps-h :focus-visible,.pf-footer :focus-visible,.ps-bottombar :focus-visible{outline-color:var(--ps-chrome-accent)}
/* Images fade in as they arrive (js adds .is-loaded); harmless without JS
   because the class is only ever added, never required. */
img.ps-fade{opacity:0;transition:opacity .35s ease}
img.ps-fade.is-loaded{opacity:1}
*{box-sizing:border-box}
html,body{margin:0}
body{
  font-family:var(--ps-font); font-size:16px; line-height:1.7; color:var(--ps-text);
  background:var(--ps-bg); -webkit-font-smoothing:antialiased; font-synthesis:none;
}
h1,h2,h3,h4,h5,h6{font-family:var(--ps-font-heading);font-weight:400;line-height:1.1;letter-spacing:.01em}
a{color:var(--ps-teal);text-underline-offset:2px}
img{max-width:100%}

/* ============ HEADER (real .ps-h) ============ */
.ps-h{position:sticky;top:0;left:0;right:0;z-index:1000;background:var(--ps-chrome-bg);
  border-bottom:1px solid var(--ps-chrome-border);box-shadow:var(--ps-chrome-shadow);font-family:var(--ps-font)}
.ps-h-inner{max-width:var(--ps-content);margin:0 auto;padding:18px 24px;display:flex;
  align-items:center;justify-content:space-between;gap:24px}
.ps-h-brand{display:inline-flex;align-items:center;gap:10px;color:var(--ps-chrome-text);
  text-decoration:none;font-weight:900;letter-spacing:.5px;font-size:18px}
.ps-h-brand:hover{color:var(--ps-chrome-accent)}
.ps-h-brand-mark{font-size:22px;line-height:1}
.ps-h-brand-text{text-transform:uppercase;font-family:var(--ps-font-heading)}
.ps-h-nav{display:flex;align-items:center;gap:8px}
.ps-h-link{color:var(--ps-chrome-text);text-decoration:none;text-transform:uppercase;font-weight:700;
  font-size:13px;letter-spacing:.6px;padding:10px 14px;border-radius:6px;white-space:nowrap;
  transition:color .15s,background .15s}
.ps-h-link:hover{color:var(--ps-chrome-accent);background:var(--ps-chrome-hover)}
.ps-h-cta{background:var(--ps-yellow);padding:10px 20px;border-radius:6px;font-size:clamp(14px,1.1vw,16px);
  box-shadow:0 4px 14px rgba(247,195,44,.28);color:#fff !important;font-weight:900 !important;letter-spacing:.03em}
.ps-h-cta:hover{background:var(--ps-yellow-hover);transform:translateY(-1px)}
/* Theme toggle — one icon button in the desktop nav; Light/Dark/Auto in the burger. */
.ps-h-theme{display:inline-flex;align-items:center;justify-content:center;width:38px;height:38px;border-radius:999px;
  border:1px solid var(--ps-chrome-line);background:transparent;color:var(--ps-chrome-text);cursor:pointer;padding:0;
  transition:border-color .15s,background .15s,color .15s}
.ps-h-theme:hover{border-color:var(--ps-chrome-accent);color:var(--ps-chrome-accent)}
.ps-h-theme svg{width:18px;height:18px}
/* ⚠️ THE ICON SHOWS THE CHOICE, NOT THE EFFECT. Keyed on data-effective, Auto
   was invisible: on a device in dark mode it drew the same moon as an explicit
   Dark, so the control had three states and two faces and you could not tell
   which one you were in. */
.ps-h-theme .ps-h-theme-moon,
.ps-h-theme .ps-h-theme-auto{display:none}
.ps-h-theme[data-choice="dark"] .ps-h-theme-sun{display:none}
.ps-h-theme[data-choice="dark"] .ps-h-theme-moon{display:block}
.ps-h-theme[data-choice="system"] .ps-h-theme-sun{display:none}
.ps-h-theme[data-choice="system"] .ps-h-theme-auto{display:block}
.ps-h-burger{display:none;width:42px;height:42px;background:transparent;border:0;cursor:pointer;
  flex-direction:column;gap:5px;align-items:center;justify-content:center;padding:0}
/* ⚠️ --ps-chrome-text, NOT --ps-surface. --ps-surface is #121b2e in the dark
   theme, so the three burger bars were being painted near-black on a black
   header — invisible on every phone in dark mode. Found while tokenising; it
   was never reported because the tap target still worked. */
.ps-h-burger span{display:block;width:24px;height:2.5px;background:var(--ps-chrome-text);border-radius:2px;transition:transform .18s,opacity .18s}
.ps-h-burger[aria-expanded="true"] span:nth-child(1){transform:translateY(7.5px) rotate(45deg)}
.ps-h-burger[aria-expanded="true"] span:nth-child(2){opacity:0}
.ps-h-burger[aria-expanded="true"] span:nth-child(3){transform:translateY(-7.5px) rotate(-45deg)}
.ps-h-mobile{display:flex;flex-direction:column;gap:4px;padding:12px 18px 20px;background:var(--ps-chrome-panel);
  border-top:1px solid var(--ps-chrome-border)}
.ps-h-mobile[hidden]{display:none}
.ps-h-mobile-link{color:var(--ps-chrome-text);text-decoration:none;text-transform:uppercase;font-weight:700;
  font-size:14px;letter-spacing:.6px;padding:14px 12px;border-radius:8px}
.ps-h-mobile-link:hover{background:var(--ps-chrome-hover);color:var(--ps-chrome-accent)}
.ps-h-mobile-link.ps-h-cta{text-align:center;background:var(--ps-yellow);color:#fff;margin:6px 0 10px}
/* Desktop shows the toggle inside the nav; the mobile pair stays hidden. */
.ps-h-theme--mobile{display:none}
.ps-h-actions{display:none}
@media(max-width:960px){
  .ps-h-nav{display:none}
  .ps-h-burger{display:flex}
  /* ⚠️ Same icon and size as the desktop one on purpose — it is the same
     control, and a phone-only variant would read as a different feature.
     The gap is small and the pair is one flex child, so the two read as a
     group at the right edge rather than as two unrelated buttons. */
  .ps-h-actions{display:flex;align-items:center;gap:2px}
  .ps-h-theme--mobile{display:inline-flex}
  .ps-h-inner{padding:14px 18px}
}

/* ============ BUTTONS (real .ph-btn) ============ */
.ph-btn{display:inline-block;background:var(--ps-yellow);text-decoration:none !important;text-transform:uppercase;
  font-size:clamp(16px,1.4vw,19px);padding:14px 32px;border-radius:6px;border:0;
  box-shadow:0 6px 18px rgba(247,195,44,.28);transition:transform .15s,box-shadow .15s,background .15s;
  cursor:pointer;color:#fff !important;font-weight:900 !important;letter-spacing:.03em}
.ph-btn:hover{background:var(--ps-yellow-hover);transform:translateY(-2px);box-shadow:0 10px 24px rgba(217,168,21,.35)}
.ph-btn:active{transform:translateY(0);box-shadow:0 4px 12px rgba(217,168,21,.3)}
.ph-btn-on-dark{box-shadow:0 6px 22px rgba(0,0,0,0.35)}

/* ============ SECTIONS ============ */
.ph-section{width:100%;max-width:100%;position:relative;padding:100px 24px}
.ph-section-title{font-size:clamp(28px,3.5vw,44px);font-weight:400;text-transform:uppercase;
  letter-spacing:.01em;margin:0 0 1.5rem;color:#fff;text-align:center}
.ph-section-title--dark{color:var(--ps-heading)}

/* Hero — photo of real stones under a navy scrim; ONE primary CTA. */
.ph-hero{min-height:600px;padding:120px 24px 72px;background-size:cover;background-position:center 40%;
  background-color:#0b1530;text-align:center;display:flex;align-items:center;justify-content:center}
.ph-hero-overlay{position:absolute;inset:0;pointer-events:none;
  background:linear-gradient(180deg,rgba(11,21,48,.55) 0%,rgba(11,21,48,.62) 55%,rgba(11,21,48,.82) 100%)}
.ph-hero-inner{position:relative;max-width:900px;margin:0 auto}
.ph-hero-eyebrow{margin:0 0 16px;font-size:12px;font-weight:700;letter-spacing:2.2px;text-transform:uppercase;color:var(--ps-yellow)}
.ph-hero-title{font-size:clamp(34px,5.4vw,64px);font-weight:400;text-transform:uppercase;letter-spacing:.5px;
  line-height:1.05;color:var(--ps-white);margin:0 0 20px;text-shadow:0 2px 12px rgba(0,0,0,.25)}
.ph-hero-break{display:none}
@media(max-width:700px){.ph-hero-break{display:inline}}
.ph-hero-sub{font-family:var(--ps-font-prose);font-size:clamp(17px,1.6vw,21px);letter-spacing:0;text-transform:none;
  color:rgba(255,255,255,.88);line-height:1.55;max-width:640px;margin:0 auto 34px;font-weight:400}
.ph-hero-actions{display:flex;gap:14px;justify-content:center;align-items:center;flex-wrap:wrap;margin:0 0 44px}
.ph-btn-lg{padding:16px 36px;font-size:clamp(16px,1.4vw,19px)}
.ph-btn-ghost{display:inline-block;padding:15px 30px;border-radius:6px;border:2px solid rgba(255,255,255,.55);
  color:#fff;text-decoration:none;text-transform:uppercase;font-weight:800;letter-spacing:.03em;font-size:clamp(14px,1.2vw,16px);
  background:rgba(255,255,255,.06);backdrop-filter:blur(6px);transition:border-color .15s,background .15s,transform .15s}
.ph-btn-ghost:hover{border-color:#fff;background:rgba(255,255,255,.14);transform:translateY(-2px)}
/* Counters — a slim strip of three linked stats. Was three tall glass cards
   that filled a whole phone screen before any action was visible. */
.ph-counters{list-style:none;padding:0;margin:0 auto;display:inline-flex;align-items:stretch;
  background:rgba(255,255,255,.08);border:1px solid rgba(255,255,255,.16);border-radius:999px;backdrop-filter:blur(10px)}
.ph-counters li{display:flex}
.ph-counters li+li{border-left:1px solid rgba(255,255,255,.16)}
.ph-counter{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:2px;
  padding:12px 28px;text-decoration:none;color:#fff;transition:background .15s;border-radius:999px}
.ph-counter:hover{background:rgba(255,255,255,.08)}
.ph-counter-num{display:block;font-size:clamp(22px,2.6vw,32px);font-weight:400;font-family:var(--ps-font-heading);
  color:var(--ps-yellow);line-height:1}
.ph-counter-label{display:block;font-size:12px;font-weight:700;text-transform:uppercase;letter-spacing:1.4px;
  color:rgba(255,255,255,.8);font-family:var(--ps-font)}
.ph-counter-link{text-decoration:none;color:inherit;display:block}

/* Goal */
/* ⚠️ THE IMAGE LIVES HERE, NOT IN AN INLINE style= ON THE SECTION. An inline
   background-image beats every stylesheet rule, so while the blade set it the
   theme could not swap it — which is why the band stayed a black world map on
   a light page. */
.ph-goal{padding:140px 24px;background-image:var(--ph-goal-map);background-size:cover;
  background-position:center;background-color:var(--ph-goal-ground);text-align:center}
.ph-goal-inner{position:relative;max-width:820px;margin:0 auto}
/* ⚠️ NOT the brand yellow on light: this is display type at 60-140px, so the
   WCAG large-text floor of 3:1 applies and #F7C32C scores 1.7:1 on the light
   band. --ph-goal-number carries navy there and yellow in the dark theme. */
.ph-bignum{font-size:clamp(60px,11vw,140px);font-weight:400;font-family:var(--ps-font);color:var(--ph-goal-number);
  line-height:1;margin:0 0 18px;letter-spacing:-2px}
.ph-goal-sub{font-size:clamp(15px,1.6vw,18px);text-transform:uppercase;letter-spacing:2px;
  color:var(--ps-heading);margin:0 0 36px;font-weight:700;font-family:var(--ps-font)}
.ph-goal-feet{display:block;margin:1.5rem auto;max-width:120px;height:auto;filter:var(--ph-goal-feet-filter)}
.ph-milestone{max-width:520px;margin:0 auto 8px}
.ph-milestone-row{display:flex;justify-content:space-between;gap:16px;font-size:13px;color:var(--ps-muted);margin-bottom:8px;letter-spacing:.2px}
.ph-milestone-row strong{color:var(--ps-heading);font-weight:700}
.ph-milestone-next{text-align:right}
/* The track keeps the theme's own border colour; the FILL stays brand yellow
   in both, because a bar is a shape rather than text — the contrast rule that
   rules yellow out for the big number does not apply to it. */
.ph-milestone-bar{height:10px;border-radius:999px;background:var(--ps-surface-2);overflow:hidden;border:1px solid var(--ps-border)}
.ph-milestone-fill{display:block;height:100%;border-radius:999px;background:linear-gradient(90deg,var(--ps-yellow),#ffd76a);
  box-shadow:0 0 18px rgba(247,195,44,.55);transition:width .8s cubic-bezier(.2,.8,.2,1)}

/* How it works — light canvas (was a teal band); the illustrations carry the colour */
.ph-how{background:var(--ps-surface);text-align:center;padding:96px 24px 80px}
.ph-how-inner{max-width:1100px;margin:0 auto}
.ph-how-grid{display:grid;grid-template-columns:repeat(4,1fr);gap:28px 24px;margin:0 0 44px}
.ph-how-cell{display:flex;flex-direction:column;align-items:center;text-align:center;color:var(--ps-text)}
.ph-how-label{margin:0 0 18px;font-size:clamp(13px,1.2vw,15px);font-weight:800;text-transform:uppercase;
  letter-spacing:.6px;line-height:1.35;color:var(--ps-heading);font-family:var(--ps-font)}
.ph-how-icon{display:block;width:100%;max-width:200px;height:auto;transition:transform .25s}
.ph-how-cell:hover .ph-how-icon{transform:translateY(-4px)}
@media(max-width:1023px){.ph-how-grid{grid-template-columns:repeat(2,1fr);gap:36px 24px}.ph-how-icon{max-width:180px}}
@media(max-width:500px){.ph-how{padding:72px 18px 56px}.ph-how-icon{max-width:140px}}

/* Latest stones — photo cards on the off-white canvas; a scroll-snap strip ≤760px */
.ph-latest{background:var(--ps-bg);text-align:center;padding:88px 24px 96px}
.ph-latest-inner{max-width:1100px;margin:0 auto}
.ph-latest-head{display:flex;align-items:baseline;justify-content:space-between;gap:16px;margin-bottom:8px;text-align:left}
.ph-latest-head .ph-section-title{margin:0;text-align:left}
.ph-latest-all{font-size:13px;font-weight:700;letter-spacing:.6px;text-transform:uppercase;color:var(--ps-heading);text-decoration:none;white-space:nowrap;
  border-bottom:2px solid var(--ps-yellow);padding-bottom:2px}
.ph-latest-all:hover{color:var(--ps-teal)}
.ph-latest-empty{color:var(--ps-muted);margin:24px 0}
.ph-stones-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:22px;margin:28px 0 0;text-align:left}
.ph-stone-card{display:block;background:var(--ps-surface);border:1px solid var(--ps-border);
  border-radius:var(--ps-radius);overflow:hidden;text-decoration:none !important;color:var(--ps-text);
  box-shadow:var(--ps-shadow-sm);transition:transform .2s,box-shadow .2s,border-color .2s}
.ph-stone-card:hover{transform:translateY(-4px);border-color:var(--ps-yellow);box-shadow:var(--ps-shadow-md)}
.ph-stone-img{position:relative;aspect-ratio:4/3;background:var(--ps-border);overflow:hidden;display:flex;align-items:center;justify-content:center}
.ph-stone-img img{width:100%;height:100%;object-fit:cover;display:block;transition:transform .5s ease}
.ph-stone-card:hover .ph-stone-img img{transform:scale(1.04)}
.ph-stone-placeholder{font-size:48px;color:rgba(15,23,42,.35)}
.ph-stone-num{position:absolute;left:10px;top:10px;font-size:12px;font-weight:800;color:#111;letter-spacing:.4px;
  background:var(--ps-yellow);border-radius:999px;padding:4px 10px;box-shadow:0 2px 8px rgba(0,0,0,.18)}
.ph-stone-info{padding:14px 16px 16px;display:flex;flex-direction:column;gap:3px}
.ph-stone-loc{font-size:14px;font-weight:700;color:var(--ps-text);line-height:1.35;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}
.ph-stone-country{font-size:12px;color:var(--ps-muted)}
@media(max-width:760px){
  .ph-latest{padding:64px 0 72px}
  .ph-latest-inner{padding:0 18px}
  .ph-latest-head{flex-wrap:wrap}
  .ph-stones-grid{display:flex;gap:14px;overflow-x:auto;scroll-snap-type:x mandatory;padding:6px 18px 18px;margin:20px -18px 0;
    scrollbar-width:none;-webkit-overflow-scrolling:touch}
  .ph-stones-grid::-webkit-scrollbar{display:none}
  .ph-stone-card{flex:0 0 72vw;max-width:300px;scroll-snap-align:start}
}
@media(max-width:700px){
  .ph-section{padding:70px 18px}
  .ph-hero{min-height:560px;padding:96px 18px 56px}
  .ph-hero-actions{flex-direction:column;gap:12px;margin-bottom:34px}
  .ph-hero-actions .ph-btn,.ph-hero-actions .ph-btn-ghost{width:100%;max-width:340px;text-align:center}
  .ph-counters{display:flex;width:100%;max-width:420px;border-radius:16px}
  .ph-counters li{flex:1}
  .ph-counter{flex:1;padding:12px 8px;border-radius:0}
  .ph-counter-label{font-size:11px;letter-spacing:.8px}
}

/* ============ SHARED SUBPAGE CHROME ============ */
/* Navy banner used atop /stones, single stone, contributor, countries, submit, faq */
/* ── THE PAGE BANNER. One navy band, used by every page that has one:
   /stones, /countries, /contributor, /submit-a-stone, /search, and (since the
   consistency pass) /faq, /about, /privacy-policy, /terms-of-use and /saved.

   Those last five used to carry a second banner, .ps-page-header — pure black
   instead of navy, centred instead of left, UPPERCASE, 44px instead of 42, and
   a bold uppercase subtitle in the body font instead of prose. Two banners is
   what made the site feel like two sites; the heights were within a pixel of
   each other by accident, so what actually read as inconsistent was the colour,
   the alignment and the case.

   ⚠️ THE INNER COLUMN IS A VARIABLE, and it has to be. The banner is left
   aligned, so its title only looks right when it starts exactly where the page's
   own text starts — and the three kinds of page do not agree on that: an archive
   reads at --ps-content (min(1600px,92vw)), long-form prose at min(1000px,92vw)
   (deliberately narrower for line length), /saved at 820px. Give them all one
   width and the title floats ~160px to the left of its own text on a wide
   screen, which looks worse than the two banners did. Measured at 1440px: the
   prose column starts at 220px, and --ss-hero--prose lands the title on 220px. */
/* ── SMALL PILL ACTION (Share, Copy link, Save offline) ───────────────────
   ⚠️ THIS LIVED INSIDE stones/show.blade.php's <style> BLOCK, so it existed on
   exactly one page. The contributor profile used the same class and got NONE of
   it: no border-radius (a square box instead of a pill), no `font-family:
   inherit` (browser sans-serif next to a page set in mono), no height or padding
   (default button cramping). Only its two colour overrides applied, which is why
   it looked like a stray form control rather than a button. Reported as "the
   share button looks weird" — it was unstyled, not badly styled.

   Shared here so every page that uses the class gets the button. ── */
.ss-iconbtn{
  display:inline-flex;align-items:center;gap:7px;
  height:36px;padding:0 14px;
  border-radius:999px;border:1px solid var(--ps-border);
  background:var(--ps-surface);color:var(--ps-heading);
  font-family:inherit;font-size:13px;font-weight:700;text-decoration:none;
  cursor:pointer;white-space:nowrap;
  transition:border-color .15s,box-shadow .15s,transform .15s,background .15s;
}
.ss-iconbtn svg{width:16px;height:16px;flex:0 0 16px}
.ss-iconbtn:hover{border-color:var(--ps-navy);box-shadow:0 6px 16px rgba(15,23,42,.10);transform:translateY(-1px)}
.ss-iconbtn:focus-visible{outline:3px solid var(--ps-yellow);outline-offset:2px}
.ss-iconbtn[aria-disabled="true"]{opacity:.4;pointer-events:none}

.ss-hero{background:var(--ps-navy);color:#fff;padding:44px 20px}
.ss-hero-inner{max-width:var(--ps-hero-width,var(--ps-content));margin:0 auto}
.ss-hero h1{color:#fff;font-size:clamp(26px,4vw,42px);margin:0}
.ss-hero p{color:rgba(255,255,255,.75);margin:6px 0 0;font-family:var(--ps-font-prose)}

/* Long-form pages — FAQ, About, Privacy, Terms. Horizontal padding tracks
   .ps-section (24px, 16px on mobile) so the two columns share an edge at every
   width, not just wide ones.

   ⚠️ NO WIDTH OVERRIDE ANY MORE, and that is the fix (owner, 2026-08-19: these
   pages "should have the header in the same position as Stones, Countries,
   Contributors"). This used to set --ps-hero-width to min(1000px,92vw) so the
   title started where the prose started — correct while .ps-section-inner was
   also 1000px. When the owner asked for these pages to run full width, only the
   CONTENT was widened, so the banner was left as the one narrow thing on the
   page: at 1440px its title sat ~160px to the LEFT of the very text it
   introduces, and at a different place again from every archive banner.

   Falling through to the default --ps-content puts all four banners, all three
   archive banners and every prose column on the same left edge. The padding
   stays 24px to match .ps-section; it makes no difference at wide widths (the
   92vw cap binds first) and keeps the gutters equal where it does. */
.ss-hero--prose{padding-left:24px;padding-right:24px}

/* (There was a .ss-hero--narrow here for /saved, back when that page read at
   820px. It now uses the site-wide content width like every other archive, so
   the default banner already lines up and the modifier had no users left.) */

@media(max-width:600px){
  .ss-hero--prose{padding-left:16px;padding-right:16px}
}
.section{padding:48px 0}
.section-inner{max-width:var(--ps-content);margin:0 auto;padding:0 20px}
.section h2{font-size:26px;margin:0 0 20px;color:var(--ps-heading)}

/* Generic stone card grid (stones archive, profiles) — light theme */
.grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(240px,1fr));gap:20px}
.card{background:var(--ps-surface);border:1px solid var(--ps-border);border-radius:14px;overflow:hidden;
  text-decoration:none;color:inherit;display:flex;flex-direction:column;transition:transform .15s,box-shadow .15s,border-color .15s}
.card:hover{transform:translateY(-3px);box-shadow:var(--ps-shadow-md);border-color:var(--ps-yellow)}
.card .ph img{transition:transform .5s ease}
.card:hover .ph img{transform:scale(1.04)}
.card .ph{aspect-ratio:4/3;background:var(--ps-surface-2) center/cover;display:flex;align-items:center;justify-content:center;color:#aeb4ac;font-size:40px}
.card .body{padding:14px 16px}
.card .num{color:var(--ps-yellow);font-weight:800;font-size:13px;letter-spacing:.4px}
.card h3{font-family:var(--ps-font);font-size:15px;font-weight:700;margin:4px 0 6px}
.card .loc{font-size:13px;color:var(--ps-muted)}
.badge{display:inline-block;font-size:12px;font-weight:700;padding:2px 9px;border-radius:20px;background:#eef1ec;color:#555;margin-right:6px}
.badge.golden{background:#fef3c7;color:#92400e}
.badge.special{background:#ede9fe;color:#6d28d9}
.btn{display:inline-block;background:var(--ps-yellow);color:#fff;text-decoration:none;font-weight:700;
  padding:11px 24px;border-radius:6px;text-transform:uppercase;letter-spacing:.03em;font-size:14px;border:0;cursor:pointer}
.empty{background:var(--ps-surface);border:1px dashed var(--ps-border);border-radius:12px;padding:48px 24px;text-align:center;color:var(--ps-muted)}
.empty h3{font-family:var(--ps-font);color:var(--ps-text);margin:0 0 8px}
.empty code{background:var(--ps-surface-2);padding:2px 7px;border-radius:4px;font-size:13px}
.ss-filter{padding:9px 12px;border:1px solid var(--ps-border);border-radius:6px;font-family:var(--ps-font);font-size:14px;background:var(--ps-input-bg);color:var(--ps-text)}
.lb{width:100%;border-collapse:collapse;background:var(--ps-surface);border:1px solid var(--ps-border);border-radius:12px;overflow:hidden}
.lb th,.lb td{text-align:left;padding:12px 16px;border-bottom:1px solid var(--ps-border);font-size:14px}
.lb th{background:var(--ps-surface-2);font-size:12px;text-transform:uppercase;letter-spacing:.5px;color:var(--ps-muted)}
.lb a{color:var(--ps-teal);font-weight:600}

/* ============ SEARCH SUGGESTIONS (js/suggest.js) ============ */
.ps-suggest{position:absolute;left:0;right:0;top:100%;z-index:1300;text-align:left}
.ps-suggest-list{list-style:none;margin:6px 0 0;padding:6px;background:var(--ps-surface);border:1px solid var(--ps-border);
  border-radius:12px;box-shadow:var(--ps-shadow-md);max-height:min(420px,60vh);overflow:auto}
.ps-suggest-list[hidden]{display:none}
.ps-suggest-item{margin:0}
.ps-suggest-link{display:flex;align-items:center;gap:10px;padding:8px 10px;border-radius:8px;text-decoration:none;color:var(--ps-text)}
.ps-suggest-item.is-active .ps-suggest-link,.ps-suggest-link:hover{background:var(--ps-row-hover,#eff6ff)}
.ps-suggest-link img,.ps-suggest-ph{flex:0 0 36px;width:36px;height:36px;border-radius:8px;object-fit:cover;background:var(--ps-surface-2);
  display:inline-flex;align-items:center;justify-content:center;font-weight:800;color:var(--ps-muted);font-size:15px}
.ps-suggest-text{display:flex;flex-direction:column;min-width:0;line-height:1.3}
.ps-suggest-title{font-size:14px;font-weight:700;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;color:var(--ps-heading)}
.ps-suggest-meta{font-size:11px;color:var(--ps-muted);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.ps-suggest-all{justify-content:center;font-size:13px;font-weight:700;color:var(--ps-teal);border-top:1px solid var(--ps-border);border-radius:0;margin-top:4px;padding-top:10px}
/* The footer search box follows the chrome theme; its suggestion list keeps the
   page surface in both themes, which is what makes it read as a card over it. */
.pf-search .ps-suggest{top:auto;bottom:100%}
.pf-search .ps-suggest-list{margin:0 0 6px}

/* ============ FOOTER (real .pf-* — 3-column dark) ============ */
.pf-footer{background:var(--ps-chrome-bg);color:var(--ps-chrome-muted);font-family:var(--ps-font);
  padding:48px 24px 32px;border-top:1px solid var(--ps-chrome-border);position:relative;z-index:1000}
.pf-footer-inner{max-width:1000px;margin:0 auto;display:grid;grid-template-columns:1.3fr 1fr 1fr;gap:40px;align-items:center}
@media(min-width:601px){.pf-footer-inner{max-width:var(--ps-content)}}
.pf-tagline{margin:0 0 6px;font-size:13px;color:var(--ps-chrome-text);font-style:italic;line-height:1.5}
.pf-copy{margin:0;font-size:13px;color:var(--ps-chrome-muted);line-height:1.6}
.pf-copy a{color:var(--ps-chrome-link);text-decoration:none}.pf-copy a:hover{color:var(--ps-chrome-text)}
.pf-search{display:flex;align-items:stretch;width:100%;max-width:320px;margin:0 auto;
  background:var(--ps-chrome-field);border:1px solid var(--ps-chrome-line);border-radius:999px;overflow:hidden;
  transition:border-color .15s,background .15s}
.pf-search:focus-within{border-color:var(--ps-chrome-accent);background:var(--ps-chrome-hover)}
.pf-search input[type=search]{flex:1;background:transparent;border:0;outline:none;color:var(--ps-chrome-text);
  font-family:var(--ps-font);font-size:14px;padding:10px 16px;min-width:0}
.pf-search input[type=search]::placeholder{color:var(--ps-chrome-muted)}
.pf-search button{background:transparent;border:0;color:var(--ps-chrome-accent);padding:0 14px;cursor:pointer;
  display:inline-flex;align-items:center;justify-content:center}
.pf-search button:hover{color:var(--ps-chrome-text)}
.pf-col-links{justify-self:end}
.pf-links{display:flex;flex-direction:column;gap:10px;align-items:flex-end}
.pf-links a{color:var(--ps-chrome-muted);font-size:14px;font-weight:600;text-decoration:none;transition:color .15s}
.pf-links a:hover{color:var(--ps-chrome-accent)}
@media(max-width:760px){
  .pf-footer{padding:36px 18px calc(28px + 56px + env(safe-area-inset-bottom))}
  .pf-footer-inner{grid-template-columns:1fr;gap:24px;text-align:center}
  .pf-col-links{justify-self:stretch}
  .pf-links{flex-direction:row;flex-wrap:wrap;justify-content:center;gap:8px 18px;align-items:center}
  .pf-search{max-width:100%}
}
@media(max-width:600px){
  /* 16px inputs on mobile → iOS Safari does not zoom the page on focus.
     Same rule the archive filters and the submit form live by (archive.css);
     the footer search was the one input left at 14px, and since the footer is
     on every page it was the only zoom trigger site-wide. Desktop stays 14px. */
  .pf-search input[type=search]{font-size:16px}
}

/* ============ MOBILE BOTTOM TAB BAR (real .ps-bottombar) ============ */
.ps-bottombar{display:none}
@media(max-width:960px){
  .ps-bottombar{position:fixed;left:0;right:0;bottom:0;z-index:1100;display:flex;align-items:stretch;
    height:56px;background:var(--ps-chrome-bg);border-top:1px solid var(--ps-chrome-border);
    padding-bottom:env(safe-area-inset-bottom);box-sizing:content-box}
  /* ⚠️ FIVE TABS NOW, so each gets ~20% of the width — 75px at 375px and 64px
     on a 320px iPhone SE. `min-width:0` is what lets flex actually shrink them
     (a flex item's default min-width is auto, i.e. its content, which would
     push the bar wider than the screen and give the whole PAGE a horizontal
     scroll — the exact bug this project has a documented history of).

     ⚠️ THE LABEL MUST NOT WRAP. "Search" is the longest at six characters, and
     in IBM Plex Mono at 11px that is ~43px including letter-spacing — inside
     64px with room to spare. A seventh tab would break that, which is why
     Countries and Contributors stay in the burger. `white-space:nowrap` makes
     the failure visible (an ellipsis) instead of silently doubling the bar's
     height and pushing the icons out of alignment. */
  .ps-bb-tab{flex:1;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:3px;
    min-width:0;color:var(--ps-chrome-muted);font-size:11px;font-weight:700;letter-spacing:.5px;
    text-transform:uppercase;text-decoration:none;-webkit-tap-highlight-color:transparent}
  .ps-bb-tab > span{max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
  .ps-bb-tab svg{width:22px;height:22px;display:block;flex:none}
  .ps-bb-tab.ps-bb-active{color:var(--ps-chrome-accent)}
  /* THE + SITS INSIDE THE BAR, NOT ON TOP OF IT.
     It used to be lifted by `margin-top:-22px` so half the disc floated above
     the bar — the classic raised FAB. On this site it read as a button that had
     escaped its container: it overlapped whatever the page was showing behind
     it, and on the archives it landed on top of the last row. The owner asked
     for it contained, so the lift is gone and the disc is sized to fit the
     56px bar with room to breathe.

     ⚠️ The ring is now the same yellow as the fill rather than a punch-through
     of the bar colour: with no overlap there is nothing to punch through, and a
     3px chrome-coloured ring inside the bar just made the disc look smaller.

     The + keeps the brand yellow in BOTH themes because it is a FILL — the ink
     sits on the yellow rather than the yellow on the ground. */
  /* 44px is the accessibility floor for a touch target and also the widest the
     disc can be inside a 56px bar with breathing room; it still fits a 64px tab
     at 320px. `flex:none` stops it being squeezed by the flex row when the two
     new labels compete for space. */
  .ps-bb-addicon{width:44px;height:44px;flex:none;background:var(--ps-yellow);color:#111;
    border-radius:50%;display:flex;align-items:center;justify-content:center;
    box-shadow:0 2px 8px rgba(0,0,0,.28)}
  .ps-bb-addicon svg{width:22px;height:22px}
  /* No caption under this one, so the disc centres in the tab instead of
     sitting above a label. */
  .ps-bb-tab.ps-bb-add{justify-content:center;gap:0}
  body{padding-bottom:calc(56px + env(safe-area-inset-bottom))}
  body.is-map{padding-bottom:0}
}
/* Narrowest phones (iPhone SE and friends): 64px per tab. The icons stay at
   22px — shrinking a touch target to fit a caption is the wrong trade — so the
   caption gives up its letter-spacing instead. */
@media(max-width:360px){
  .ps-bb-tab{font-size:10px;letter-spacing:.2px}
}

/* ============ MAP ============ */
/* ⚠️ THE HEADER HEIGHT IS MEASURED, NOT GUESSED — see --ps-header-h, set by the
   inline script at the top of map.blade.php. It used to be hard-coded as 61px and
   was wrong at BOTH breakpoints: the real header is 71px on mobile and 81px on
   desktop, so the map ran 10px / 20px past the bottom of the viewport. That
   pushed Leaflet's bottom controls under the mobile tab bar and pushed the
   OpenStreetMap ATTRIBUTION off-screen entirely on desktop — that is a licence
   credit, not decoration. The values below are only the pre-script fallback.
   Measuring is safe here specifically because the map is Leaflet: with JS off
   there is no map to size at all.

   ⚠️ 100dvh, NOT 100vh. On iOS Safari 100vh is the height with the URL bar
   COLLAPSED, so a 100vh map is always taller than what you can see — the same
   overflow, but intermittent and far harder to reproduce. */
#penguinstones-map{height:calc(100dvh - var(--ps-header-h, 81px));width:100%;background:#b9d6df}  /* ocean tone under the tiles: any sub-tile gap at ±85° reads as sea, not as a hole */
@media(max-width:960px){
  .is-map #penguinstones-map{height:calc(100dvh - var(--ps-header-h, 71px))}
  /* ⚠️ The map now runs FULL HEIGHT behind the bottom tab bar, and Leaflet's own
     controls are lifted clear of it instead. Shrinking the map by the bar height
     was the old approach, and it coupled the control positions to the header
     constant: get that constant wrong and the controls vanish. Lifting them is
     independent of everything above the map. */
  .is-map .leaflet-bottom{bottom:calc(57px + env(safe-area-inset-bottom))}
}

/* ⚠️ NO FOOTER ON THE MAP PAGE, AND THIS IS WHY THE MAP "DIDN'T SHOW NICELY".
   Measured on an iPhone 17 at 375x812: the map is exactly one viewport tall
   (header 71 + map 741 = 812), so the 335px footer underneath made the document
   1,199px — 387px of scroll on a page that should not scroll at all. Scrolling
   then slid the map up off the screen, leaving the footer and dead space in
   view. That is what "half the screen is blue, half loaded" was: the bottom of
   the map is Southern Ocean, and the rest was the page below it.

   Hidden at EVERY width, not just mobile — the desktop map is also
   calc(100dvh - header), so the same overflow existed there.

   ⚠️ The footer's About / Terms / Privacy links stay reachable from the header
   menu on this page, which is the only reason hiding it is acceptable. */
body.is-map .pf-footer{display:none}

/* ⚠️ THE MAP'S HEIGHT IS NOW THE LEFTOVER SPACE, NOT AN ARITHMETIC GUESS.
   `calc(100dvh - var(--ps-header-h))` needed a JS-measured constant to be right
   at all times, and it kept going stale. Measured at 812x375: --ps-header-h read
   124px while the real offset above the map was 103px — the deploy banner had
   reflowed from two lines to one when the viewport widened, and the constant did
   not follow. A wrong constant makes the map overshoot the viewport, which makes
   the page scroll, which slides the map off the screen.

   A flex column has no constant to be wrong about: the header takes what it
   needs, the map takes the rest, and it re-solves itself on rotation, on a
   banner reflow, on a webfont swap and on every URL-bar move — the whole class
   of bug rather than the instances of it.

   ⚠️ `min-height:0` is load-bearing. A flex item's default `min-height:auto`
   refuses to shrink below its content, so without it the map can still push the
   page taller than the viewport — which is the exact bug this replaces. */
body.is-map{height:100dvh;display:flex;flex-direction:column;overflow:hidden}
body.is-map main{flex:1 1 auto;min-height:0;display:flex;flex-direction:column}
body.is-map #penguinstones-map{flex:1 1 auto;min-height:0;height:auto}

/* skeleton banner */
.skl{background:var(--ps-yellow);color:#111;text-align:center;padding:6px 12px;font-size:12px;font-weight:700}

/* ============ INFO PAGES (About / Terms / Privacy / FAQ) ============ */
/* Centered prose column for the long-form pages. The black banner that used
   to sit here is gone — every page now shares .ss-hero above. */
.ps-section{width:100%;padding:52px 24px}
.ps-section-white{background:var(--ps-surface)}
/* ⚠️ WAS min(1000px, 92vw) — a deliberately narrow measure for readable line
   length, and the owner overruled it: FAQ, Privacy, Terms and About are to run
   the full width the rest of the site uses on a laptop. --ps-content is the
   site-wide token (min(1600px, 92vw)), so these pages now match the archives
   and the header instead of sitting in a narrow column of their own.

   ⚠️ AND THE PARAGRAPHS ARE NOT CAPPED EITHER — see the note further down where
   the 78ch cap used to be. An earlier version of this comment said they still
   were, which was left over from the half-done state and was simply untrue. */
.ps-section-inner{max-width:var(--ps-content);margin:0 auto}
.ps-btn{display:inline-block;padding:12px 28px;border-radius:8px;font-weight:700;font-size:15px;text-decoration:none !important;transition:all .2s;font-family:var(--ps-font)}
.ps-btn:hover{opacity:.88;transform:translateY(-1px)}
.ps-btn-primary{background:var(--ps-navy);color:#fff !important}

/* Legal (Terms / Privacy) — navy headings, muted body */
.ps-legal .ps-section-inner,.ps-faq .ps-section-inner,.ps-about .ps-section-inner{text-align:left}
/* ⚠️ THE TEXT FILLS THE BLOCK — the 78ch cap that was here is GONE.
   I added it on readability grounds: a line of prose running the full 1600px is
   hard to track back to, so the band was full width and the paragraphs sat in a
   786px column inside it. The owner's reply was that it "does not work as
   wanted" and pointed at /saved, where the content simply fills its container.
   He is right that the half-measure looked worse than either extreme: a narrow
   left-hugging column inside a wide band reads as a layout bug, not a choice.

   ⚠️ THE TRADE IS REAL AND HE HAS TAKEN IT KNOWINGLY. At a maximised laptop
   window these pages now set ~150-character lines, which is roughly twice the
   length typographers recommend. /saved gets away with the same width because
   its content is short list items and cards; FAQ and the legal pages are long
   prose. If it ever reads badly, the fix is this cap coming back — not a new
   mechanism. */
.ps-legal h2{font-size:clamp(19px,2.2vw,24px);font-weight:800;color:var(--ps-heading);margin:36px 0 12px;line-height:1.3}
.ps-legal h2:first-of-type{margin-top:0}
.ps-legal p{font-family:var(--ps-font-prose);font-size:16px;line-height:1.75;color:var(--ps-text-soft);margin:0 0 16px;overflow-wrap:anywhere}
.ps-legal p strong{color:var(--ps-text)}
.ps-legal ul{margin:0 0 16px;padding-left:22px;list-style:disc}
.ps-legal li{font-family:var(--ps-font-prose);font-size:16px;line-height:1.7;color:var(--ps-text-soft);margin:0 0 8px}
.ps-legal a{color:var(--ps-teal);text-decoration:underline;font-weight:600}

/* FAQ — yellow question headings */
.ps-faq h2{color:var(--ps-yellow);font-weight:800;font-size:clamp(19px,2.2vw,24px);line-height:1.3;margin:40px 0 12px}
.ps-faq h2:first-of-type{margin-top:0}
.ps-faq p{font-family:var(--ps-font-prose);font-size:16px;line-height:1.75;color:var(--ps-text);margin:0 0 16px;overflow-wrap:anywhere}
.ps-faq p strong{color:var(--ps-text);font-weight:700}
.ps-faq ul{margin:0 0 16px;padding-left:22px;list-style:disc}
.ps-faq li{font-family:var(--ps-font-prose);font-size:16px;line-height:1.7;color:var(--ps-text);margin:0 0 8px}
.ps-faq a{color:var(--ps-teal);text-decoration:underline;font-weight:600}

/* About — yellow headings + float illustration + CTA row */
.ps-about h2{color:var(--ps-yellow);font-weight:800;font-size:clamp(19px,2.2vw,24px);line-height:1.3;margin:40px 0 12px;clear:both}
.ps-about h2:first-of-type{margin-top:0}
.ps-about p{font-family:var(--ps-font-prose);font-size:16px;line-height:1.75;color:var(--ps-text);margin:0 0 16px;overflow-wrap:anywhere}
.ps-about-figure--left{float:left;width:100%;max-width:260px;margin:4px 26px 14px 0}
.ps-about-figure--left img{display:block;width:100%;height:auto;border-radius:12px}
.ps-about-cta{clear:both;display:flex;flex-wrap:wrap;gap:12px;margin:28px 0}
.ps-about-cta .ps-btn{background:var(--ps-yellow);color:#fff !important;text-transform:uppercase;font-weight:800;border-radius:6px;border:0;box-shadow:0 6px 18px rgba(247,195,44,.28)}
.ps-about-cta .ps-btn:hover{background:var(--ps-yellow-hover);transform:translateY(-2px);opacity:1}
.ps-about-cta .ps-btn--kofi{background:var(--ps-teal);box-shadow:0 6px 18px rgba(55,149,155,.28)}
.ps-about-cta .ps-btn--kofi:hover{background:#2c7a7f}
@media(max-width:600px){
  .ps-section{padding:40px 16px}
  .ps-about-figure--left{float:none;max-width:100%;margin:0 0 16px}
  .ps-about-cta .ps-btn{width:100%;text-align:center}
}

/* ============ COOKIE CONSENT BANNER (local, WPConsent-style) ============ */
/* Bottom-fixed light bar; persists the choice in localStorage. z-index 1200 so
   it sits above the mobile bottom tab bar (1100) until a choice is made —
   deliberate, matching the live site. Hidden by default; JS reveals it if no
   prior choice. */
.ps-consent{position:fixed;left:0;right:0;bottom:0;z-index:1200;display:none;
  background:var(--ps-surface);border-top:2px solid var(--ps-yellow);box-shadow:0 -4px 20px rgba(0,0,0,.12);
  padding:16px 20px calc(16px + env(safe-area-inset-bottom))}
.ps-consent.is-open{display:block}
.ps-consent-inner{max-width:var(--ps-content);margin:0 auto;display:flex;align-items:center;gap:20px;flex-wrap:wrap}
.ps-consent-msg{flex:1;min-width:260px;font-size:13.5px;line-height:1.6;color:var(--ps-text);font-family:var(--ps-font)}
.ps-consent-msg a{color:var(--ps-teal);font-weight:600;text-decoration:underline}
.ps-consent-actions{display:flex;gap:10px;flex-wrap:wrap}
.ps-consent-btn{font-family:var(--ps-font);font-weight:700;font-size:13px;padding:9px 18px;border-radius:6px;cursor:pointer;border:1.5px solid var(--ps-border);background:var(--ps-surface);color:var(--ps-text)}
.ps-consent-btn:hover{border-color:var(--ps-heading)}
.ps-consent-btn--accept{background:var(--ps-yellow);border-color:var(--ps-yellow);color:#111}
.ps-consent-btn--accept:hover{background:var(--ps-yellow-hover);border-color:var(--ps-yellow-hover);color:#fff}
@media(max-width:600px){
  .ps-consent-inner{flex-direction:column;align-items:stretch;gap:12px}
  .ps-consent-actions{justify-content:stretch}
  .ps-consent-btn{flex:1}
}
