/* ═══════════════════════════════════════════════════════════════════════════
   quarter — Budapest.

   THE ONE IDEA: the photograph is the page, and the writing sits on paper
   underneath it. Every screen is one picture and then some prose — no cards
   inside cards, no chips over images, no gradient scrims doing the work that a
   crop should do.

   COLOUR — paper and ink, and nothing else. The photographs are the only
   colour in the app, which is why they have to be good and why the chrome
   gives them the whole width.

   TYPE — Kalice for anything that is a NAME (a district, a place, a year),
   Selecta for everything that is information. Two faces, one job each.
   ═══════════════════════════════════════════════════════════════════════════ */

@font-face{font-family:Selecta;src:url('fonts/Selecta-Regular.otf') format('opentype');font-weight:400;font-display:block}
@font-face{font-family:Selecta;src:url('fonts/Selecta-Medium.otf')  format('opentype');font-weight:500;font-display:block}
@font-face{font-family:Selecta;src:url('fonts/Selecta-Bold.otf')    format('opentype');font-weight:700;font-display:block}
@font-face{font-family:Kalice; src:url('fonts/Kalice-Regular.woff2') format('woff2');  font-weight:400;font-display:block}

:root{
  --paper:#FCFBFA;
  --shell:#EDE9E4;
  --ink:#2C2528;
  --ink-70:rgba(44,37,40,.70);
  --ink-45:rgba(44,37,40,.45);
  --ink-28:rgba(44,37,40,.28);
  --ink-12:rgba(44,37,40,.12);
  --ink-06:rgba(44,37,40,.06);

  /* the one warm accent, spent only on "this is shut" and on a saved mark */
  --flag:#A8442A;

  --glass-bg:rgba(252,250,249,.74);
  --glass-line:rgba(255,255,255,.72);
  --glass-blur:blur(26px) saturate(1.35);
  --glass-shadow:
    inset 0 1px 0 rgba(255,255,255,.60),
    0 1px 2px rgba(44,37,40,.06),
    0 14px 34px -12px rgba(44,37,40,.26);

  --r-panel:16px; --r-card:22px; --r-pill:999px;
  --ease:cubic-bezier(.22,.9,.3,1);
  --ease-long:cubic-bezier(.32,.72,0,1);
  --pop:cubic-bezier(.34,1.42,.64,1);

  --safe-top:max(14px,env(safe-area-inset-top));
  --safe-bot:env(safe-area-inset-bottom);
  --pad:20px;
  --tabh:60px;            /* the pill itself */
  --tab-gap:14px;         /* how far it floats off the bottom */
  /* what any scroller has to clear so the last row is not under the glass */
  --tab-clear:calc(var(--tabh) + var(--tab-gap) * 2 + var(--safe-bot));
}

*{margin:0;padding:0;box-sizing:border-box;-webkit-tap-highlight-color:transparent}
[hidden]{display:none!important}

html,body{height:100%}
body{
  background:var(--shell); color:var(--ink);
  font:400 15px/1.45 Selecta,ui-sans-serif,system-ui,-apple-system,sans-serif;
  letter-spacing:-.008em; -webkit-font-smoothing:antialiased;
  overscroll-behavior:none;
  display:grid; place-items:center;
}
button{font:inherit;color:inherit;background:none;border:0;cursor:pointer}
img{display:block;max-width:100%}

/* ── the frame ───────────────────────────────────────────────────────────── */

.device{display:grid;place-items:center;width:100%;height:100%}
.phone{
  position:relative;
  width:402px; height:874px;             /* iPhone 17 Pro points */
  border-radius:54px; overflow:hidden;
  background:var(--paper);
  box-shadow:
    0 0 0 1px rgba(9,9,9,.10),
    0 1px 2px rgba(9,9,9,.06),
    0 44px 90px -24px rgba(9,9,9,.30);
}
body.bare .phone{
  width:100%;height:100%;border-radius:0;box-shadow:none;
}
.hint{
  position:fixed;left:0;right:0;bottom:16px;text-align:center;
  font-size:11.5px;color:var(--ink-28);letter-spacing:.02em;pointer-events:none;
  transition:opacity .4s var(--ease);
}
.hint kbd{font:inherit;border:1px solid var(--ink-12);border-radius:4px;padding:0 4px}
.hint.gone{opacity:0}

/* Below the frame's own size there IS no frame — full bleed, real insets. */
@media (max-width:480px),(max-height:900px){
  .phone{width:100%;height:100%;border-radius:0;box-shadow:none}
  .hint{display:none}
}

/* container queries, not media queries: the framed desktop view and a real
   phone then share ONE layout and the frame is a preview, not a second design */
.app{
  container-type:inline-size;
  position:relative; width:100%; height:100%;
  background:var(--paper); overflow:hidden;
}
body.bare .app{--safe-top:max(14px,env(safe-area-inset-top))}

/* ── the stack ───────────────────────────────────────────────────────────── */

.stage{position:absolute;inset:0}

.screen{
  position:absolute; inset:0;
  overflow-y:auto; overflow-x:hidden;
  -webkit-overflow-scrolling:touch; overscroll-behavior:contain;
  background:var(--paper);
  padding-bottom:calc(var(--tab-clear) + 10px);
}
.screen::-webkit-scrollbar{width:0}

/* a pushed screen comes in from the right over the one below; the one below
   drifts a little and dims, so the stack has depth without a shadow */
.screen.pushing{animation:pushIn .42s var(--ease-long) both}
.screen.popping{animation:pushIn .34s var(--ease) reverse both}
@keyframes pushIn{from{opacity:0}to{opacity:1}}
.screen.under{transform:translateX(-14px);filter:brightness(.965);transition:transform .42s var(--ease-long),filter .42s var(--ease-long)}

/* a screen the morph is flying INTO holds its content back for a beat, so the
   photograph arrives first and the words land on it */
.screen.arriving .sheet{opacity:0;transform:translateY(10px)}
.screen .sheet{transition:opacity .34s var(--ease) .1s,transform .34s var(--ease) .1s}

/* ── chrome ──────────────────────────────────────────────────────────────── */

.top{
  position:relative; z-index:6;
  padding:calc(var(--safe-top) + 26px) var(--pad) 14px;
  background:var(--paper);
}
.top h1{
  font:400 30px/1 Kalice,Georgia,serif; letter-spacing:-.014em;
}
.top .meta{margin-top:7px;font-size:12px;color:var(--ink-45);letter-spacing:.01em}

/* the back bar floats over a hero photograph, so it is glass and it is dark */
.back{
  position:absolute; z-index:8;
  top:calc(var(--safe-top) + 4px); left:14px;
  width:38px;height:38px;border-radius:var(--r-pill);
  display:grid;place-items:center;
  background:rgba(20,18,20,.34);
  backdrop-filter:blur(14px) saturate(1.3); -webkit-backdrop-filter:blur(14px) saturate(1.3);
  box-shadow:inset 0 1px 0 rgba(255,255,255,.18);
  color:#fff;
}
.back:active{transform:scale(.94)}
.back svg{width:19px;height:19px;fill:none;stroke:currentColor;stroke-width:1.8;
  stroke-linecap:round;stroke-linejoin:round}

.keep{
  position:absolute; z-index:8;
  top:calc(var(--safe-top) + 4px); right:14px;
  width:38px;height:38px;border-radius:var(--r-pill);
  display:grid;place-items:center;
  background:rgba(20,18,20,.34);
  backdrop-filter:blur(14px) saturate(1.3); -webkit-backdrop-filter:blur(14px) saturate(1.3);
  box-shadow:inset 0 1px 0 rgba(255,255,255,.18);
  color:#fff;
}
.keep svg{width:17px;height:17px;fill:none;stroke:currentColor;stroke-width:1.7;
  stroke-linejoin:round}
.keep[aria-pressed="true"] svg{fill:#fff}
.keep:active{transform:scale(.94)}

/* ── search ──────────────────────────────────────────────────────────────── */

.find{
  margin:2px var(--pad) 0; position:relative;
  display:flex;align-items:center;gap:9px;
  height:40px;padding:0 14px;border-radius:var(--r-pill);
  background:var(--ink-06);
}
.find svg{width:15px;height:15px;flex:none;fill:none;stroke:var(--ink-45);stroke-width:1.9;
  stroke-linecap:round}
.find input{
  flex:1;min-width:0;align-self:stretch;border:0;background:none;outline:0;
  font:400 14.5px/1 Selecta,sans-serif;color:var(--ink);letter-spacing:-.005em;
}
.find input::placeholder{color:var(--ink-45)}
.find .clr{width:22px;height:22px;border-radius:var(--r-pill);display:grid;place-items:center;
  background:var(--ink-12);color:var(--ink-70);font-size:13px;line-height:1}

/* ── sections ────────────────────────────────────────────────────────────── */

.sec{padding:40px var(--pad) 0}
.sec > h2,
.sheet .sec > h2{
  font:500 10.5px/1 Selecta,sans-serif; letter-spacing:.15em; text-transform:uppercase;
  color:var(--ink-45); margin:0 0 9px;
}
.sec > .lede{
  font-size:13px;line-height:1.5;color:var(--ink-70);
  margin-bottom:18px;max-width:30em;text-wrap:pretty;
}

/* ── the cover ───────────────────────────────────────────────────────────── */

.cover{padding:14px var(--pad) 0}
.cover .shot{
  position:relative; width:100%; aspect-ratio:4/5;
  border-radius:var(--r-card); overflow:hidden; background:var(--ink-12);
}
.cover .shot img{width:100%;height:100%;object-fit:cover}
.cover .say{
  margin:16px 2px 0;
  font:400 21px/1.32 Kalice,Georgia,serif; letter-spacing:-.012em;
  text-wrap:pretty;
}
.cover .by{margin:10px 2px 0;font-size:12.5px;color:var(--ink-45)}

/* ── cards ───────────────────────────────────────────────────────────────── */

.card{display:block;width:100%;text-align:left;position:relative}
.card .shot{
  position:relative; width:100%; overflow:hidden;
  border-radius:var(--r-card); background:var(--ink-12);
}
.card .shot img{width:100%;height:100%;object-fit:cover;display:block}
.card:active .shot{transform:scale(.985)}
.card .shot{transition:transform .16s var(--ease)}

/* the quarters — a wide card with the number set INTO the picture, because a
   district's number is how it is spoken about */
.quarters{display:grid;gap:22px}
.q-card .shot{aspect-ratio:16/10}
.q-card .num{
  position:absolute; left:14px; bottom:11px; z-index:2;
  font:400 30px/1 Kalice,Georgia,serif; color:#fff;
  text-shadow:0 1px 14px rgba(0,0,0,.42);
}
.q-card .shot::after{
  content:''; position:absolute; inset:auto 0 0 0; height:52%;
  background:linear-gradient(rgba(0,0,0,0),rgba(0,0,0,.42));
}
.q-card .say{display:flex;align-items:baseline;gap:9px;margin:10px 2px 0}
.q-card .say b{font:400 20px/1.15 Kalice,Georgia,serif;letter-spacing:-.014em}
.q-card .say i{font-style:normal;font-size:12px;color:var(--ink-45);letter-spacing:0}

/* threads — two columns of portrait cards. This was a bleeding horizontal rail
   and the negative margin only holds at scrollLeft 0; snapped or nudged, the
   first card sat hard against the screen edge while every other element on the
   page began at --pad. A grid cannot lose its margin. Portrait against the
   full-width quarter cards above is also the rhythm change the rail was for. */
.rail{display:grid;grid-template-columns:1fr 1fr;gap:20px 12px}
.t-card .shot{aspect-ratio:4/5}
.t-card .say{display:block;margin:10px 2px 0}
.t-card .say b{display:block;font:400 17px/1.2 Kalice,Georgia,serif;letter-spacing:-.01em}
.t-card .say i{font-style:normal;display:block;margin-top:3px;font-size:12px;color:var(--ink-45);
  line-height:1.35;text-wrap:pretty}

/* stay — a list, because the answer is a comparison */
.stays{display:grid;gap:18px}
.s-card{display:grid;grid-template-columns:96px 1fr;gap:13px;align-items:start;text-align:left;width:100%}
.s-card .shot{aspect-ratio:1;border-radius:var(--r-panel)}
.s-card b{font:400 16px/1.2 Kalice,Georgia,serif;display:block}
.s-card i{font-style:normal;display:block;margin-top:3px;font-size:12.5px;color:var(--ink-45)}
.s-card p{margin-top:6px;font-size:13px;line-height:1.45;color:var(--ink-70);
  display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}
.s-card.no b::after{
  content:'avoid'; margin-left:7px; vertical-align:2px;
  font:500 9.5px/1 Selecta,sans-serif;letter-spacing:.09em;text-transform:uppercase;
  color:var(--flag); border:1px solid currentColor;border-radius:3px;padding:3px 4px;
}

/* ── place rows ──────────────────────────────────────────────────────────── */

.rows{display:grid}
.row{
  display:grid;grid-template-columns:1fr auto;gap:12px;align-items:baseline;
  width:100%;text-align:left;padding:13px 0;
  box-shadow:inset 0 -1px 0 var(--ink-12);
}
.rows .row:last-child{box-shadow:none}
.row b{font:400 16px/1.25 Kalice,Georgia,serif;letter-spacing:-.005em}
.row .k{font-size:11.5px;color:var(--ink-45);letter-spacing:.02em;white-space:nowrap}
.row p{grid-column:1/-1;margin-top:4px;font-size:13px;line-height:1.46;color:var(--ink-70);
  text-wrap:pretty;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}
.row.shut b{color:var(--ink-45)}
.row.shut b::after{
  content:'closed'; margin-left:8px;vertical-align:2px;
  font:500 9.5px/1 Selecta,sans-serif;letter-spacing:.09em;text-transform:uppercase;
  color:var(--flag);border:1px solid currentColor;border-radius:3px;padding:3px 4px;
}
.row .n{
  font:400 12px/1 Selecta,sans-serif;color:var(--ink-28);
  font-variant-numeric:tabular-nums;
}

/* ── a detail screen ─────────────────────────────────────────────────────── */

.hero{
  position:relative; width:100%; aspect-ratio:4/5; overflow:hidden;
  background:var(--ink-12);
}
.hero img{width:100%;height:100%;object-fit:cover}
.hero::after{
  content:''; position:absolute; inset:0;
  background:linear-gradient(rgba(0,0,0,.30) 0 14%,rgba(0,0,0,0) 42%);
  pointer-events:none;
}

/* the sheet is paper pulled up over the bottom of the photograph */
.sheet{
  position:relative; z-index:3; margin-top:-34px;
  border-radius:26px 26px 0 0; background:var(--paper);
  padding:22px var(--pad) 0; min-height:52cqh;
}
.sheet .kind{font-size:11.5px;letter-spacing:.10em;text-transform:uppercase;color:var(--ink-45)}
.sheet h2{margin-top:6px;font:400 30px/1.08 Kalice,Georgia,serif;letter-spacing:-.018em;text-wrap:balance}
.sheet h2 .sub{display:block;margin-top:6px;font-size:14px;color:var(--ink-45);letter-spacing:0}
.sheet .why{margin-top:15px;font-size:15px;line-height:1.55;text-wrap:pretty}
.sheet .why + .why{margin-top:11px}

.note{
  margin-top:16px;padding:13px 14px;border-radius:var(--r-panel);
  background:var(--ink-06);font-size:13.2px;line-height:1.5;color:var(--ink-70);text-wrap:pretty;
}
.note.warn{background:rgba(168,68,42,.07);color:#7C3520}
.note b{font-weight:500;color:var(--ink)}
.note.warn b{color:#7C3520}

.facts{margin-top:16px;display:grid;gap:0}
.fact{display:grid;grid-template-columns:76px 1fr;gap:12px;padding:9px 0;
  box-shadow:inset 0 -1px 0 var(--ink-12);font-size:13px}
.facts .fact:last-child{box-shadow:none}
.fact dt{color:var(--ink-45)}
.fact dd{color:var(--ink)}

.acts{display:flex;gap:8px;margin-top:18px;flex-wrap:wrap}
.btn{
  height:38px;padding:0 15px;border-radius:var(--r-pill);
  display:inline-flex;align-items:center;gap:7px;
  background:var(--ink-06); font-size:13.5px;
}
.btn:active{transform:scale(.97)}
.btn svg{width:15px;height:15px;fill:none;stroke:currentColor;stroke-width:1.7;stroke-linejoin:round}
.btn.on{background:var(--ink);color:var(--paper)}
.btn.on svg{fill:currentColor}

.credit{
  margin:26px 0 0;padding:14px var(--pad) 20px;
  border-top:1px solid var(--ink-12);
  font-size:11.5px;line-height:1.5;color:var(--ink-45);
}
.credit a{color:inherit}

/* ── know ────────────────────────────────────────────────────────────────── */

.know-g{display:grid;gap:0}
.kn{padding:15px 0;box-shadow:inset 0 -1px 0 var(--ink-12)}
.kn:last-child{box-shadow:none}
.kn h3{font:400 17px/1.2 Kalice,Georgia,serif;margin-bottom:6px}
.kn p{font-size:13.6px;line-height:1.55;color:var(--ink-70);text-wrap:pretty}

/* history — the year is the spine */
.hist{display:grid;gap:0}
.hx{display:grid;grid-template-columns:58px 1fr;gap:14px;padding:16px 0;
  box-shadow:inset 0 -1px 0 var(--ink-12)}
.hist .hx:last-child{box-shadow:none}
.hx .yr{font:400 14px/1.3 Kalice,Georgia,serif;color:var(--ink-45);font-variant-numeric:tabular-nums;
  padding-top:1px}
.hx h3{font:400 17.5px/1.2 Kalice,Georgia,serif;margin-bottom:6px}
.hx p{font-size:13.6px;line-height:1.55;color:var(--ink-70);text-wrap:pretty}
.hx .shot{margin-top:11px;border-radius:var(--r-panel);overflow:hidden;aspect-ratio:16/10;
  background:var(--ink-12)}
.hx .shot img{width:100%;height:100%;object-fit:cover}

/* ── saved ───────────────────────────────────────────────────────────────── */

/* Most people will open this with nothing in it, so it is a designed screen
   rather than a line of text: the guide's own photographs, faded to the paper,
   as the shape the list will take. */
.empty{padding:0 var(--pad)}
.empty .ghost{
  display:grid;grid-template-columns:1fr 1fr;gap:10px;margin-top:6px;
  opacity:.20; filter:grayscale(.5); pointer-events:none;
  -webkit-mask-image:linear-gradient(#000 0 34%,rgba(0,0,0,0) 96%);
          mask-image:linear-gradient(#000 0 34%,rgba(0,0,0,0) 96%);
}
.empty .ghost div{aspect-ratio:4/5;border-radius:var(--r-panel);overflow:hidden;background:var(--ink-12)}
.empty .ghost img{width:100%;height:100%;object-fit:cover}
.empty .say{margin-top:-186px;position:relative;z-index:2;font:400 19px/1.35 Kalice,Georgia,serif;
  max-width:19em;text-wrap:pretty}
.empty .sub{position:relative;z-index:2;margin-top:9px;font-size:13.4px;line-height:1.5;
  color:var(--ink-70);max-width:26em}

/* ── map ─────────────────────────────────────────────────────────────────── */

.mapwrap{position:absolute;inset:0}
#map{position:absolute;inset:0}
/* The tint is now mostly done in the style itself (see map.js) — this is only
   the last few per cent of warmth, because a filter strong enough to make the
   map look like paper is also strong enough to erase the river.
   The markers are DOM, not canvas, so they stay untinted either way. */
#map .mapboxgl-canvas{filter:sepia(.10) saturate(.94) contrast(1.05)}
.mapboxgl-ctrl-logo{opacity:.5}
.mapboxgl-ctrl-attrib{font:11px/1.3 Selecta,sans-serif}
.mapboxgl-ctrl-bottom-right,.mapboxgl-ctrl-bottom-left{
  margin-bottom:calc(var(--tab-clear) - 14px)}

.pin{
  width:15px;height:15px;border-radius:var(--r-pill);cursor:pointer;
  background:var(--ink); border:2.5px solid var(--paper);
  box-shadow:0 1px 5px rgba(0,0,0,.32);
  transition:transform .18s var(--pop);
}
.pin:hover{transform:scale(1.28)}
.pin.shut{background:var(--flag)}
.pin.kept{background:var(--paper);border-color:var(--ink);box-shadow:0 0 0 2.5px var(--ink) inset,0 1px 5px rgba(0,0,0,.32)}
.pin.shut.kept{background:var(--flag)}   /* closed is the fact, kept is the note */
.pin.big{transform:scale(1.5)}

.mapbar{
  position:absolute;z-index:5;left:0;right:0;
  top:calc(var(--safe-top) + 4px);
  display:flex;gap:7px;overflow-x:auto;padding:0 14px;scrollbar-width:none;
}
.mapbar::-webkit-scrollbar{height:0}
.chip{
  flex:none;height:32px;padding:0 13px;border-radius:var(--r-pill);
  font-size:12.5px;white-space:nowrap;
  background:var(--glass-bg);
  backdrop-filter:var(--glass-blur);-webkit-backdrop-filter:var(--glass-blur);
  border:1px solid var(--glass-line); box-shadow:var(--glass-shadow);
}
.chip[aria-pressed="true"]{background:var(--ink);color:var(--paper);border-color:transparent}

/* the little sheet that comes up when a pin is tapped */
.peek{
  position:absolute;z-index:6;left:10px;right:10px;
  bottom:calc(var(--tab-clear) + 6px);
  display:grid;grid-template-columns:64px 1fr auto;gap:12px;align-items:center;
  padding:10px;border-radius:20px;text-align:left;
  background:var(--glass-bg);
  backdrop-filter:var(--glass-blur);-webkit-backdrop-filter:var(--glass-blur);
  border:1px solid var(--glass-line); box-shadow:var(--glass-shadow);
  animation:peekUp .3s var(--pop) both;
}
@keyframes peekUp{from{transform:translateY(14px);opacity:0}to{transform:none;opacity:1}}
.peek .shot{width:64px;height:64px;border-radius:13px;overflow:hidden;background:var(--ink-12)}
.peek .shot img{width:100%;height:100%;object-fit:cover}
.peek b{font:400 16px/1.2 Kalice,Georgia,serif;display:block}
.peek i{font-style:normal;display:block;margin-top:3px;font-size:12px;color:var(--ink-45)}
.peek .go{width:30px;height:30px;border-radius:var(--r-pill);display:grid;place-items:center;
  background:var(--ink-06);margin-right:4px}
.peek .go svg{width:15px;height:15px;fill:none;stroke:currentColor;stroke-width:1.8;
  stroke-linecap:round;stroke-linejoin:round}

.mapmsg{
  position:absolute;inset:0;display:grid;place-content:center;gap:10px;
  padding:0 34px;text-align:center;background:var(--shell);
}
.mapmsg h3{font:400 20px/1.25 Kalice,Georgia,serif}
.mapmsg p{font-size:13.4px;line-height:1.55;color:var(--ink-70)}
.mapmsg code{font:12px ui-monospace,SFMono-Regular,Menlo,monospace;background:var(--ink-06);
  padding:2px 5px;border-radius:5px}

/* ── the morph ───────────────────────────────────────────────────────────── */

/* ONE node. It is given the source picture's rect, then the destination's, and
   a single transition carries it. No clone of the card, no FLIP library — the
   thing that moves is a real element with a real photograph in it. */
.morph{
  position:absolute; z-index:20; overflow:hidden; pointer-events:none;
  background:var(--ink-12); display:none;
}
.morph img{width:100%;height:100%;object-fit:cover}
.morph.go{
  transition:top .46s var(--ease-long),left .46s var(--ease-long),
             width .46s var(--ease-long),height .46s var(--ease-long),
             border-radius .46s var(--ease-long);
}

/* ── tabs ────────────────────────────────────────────────────────────────── */

/* A floating glass pill, not a bar welded to the bottom edge. The content runs
   underneath it and is read THROUGH it, which is the whole point of the
   surface — a bar with an opaque edge is just a footer with a blur on it. */
.tabs{
  position:absolute; z-index:10;
  left:var(--tab-gap); right:var(--tab-gap);
  bottom:calc(var(--tab-gap) + var(--safe-bot));
  height:var(--tabh);
  display:grid; grid-template-columns:repeat(4,1fr);
  border-radius:var(--r-pill);
  background:var(--glass-bg);
  backdrop-filter:var(--glass-blur); -webkit-backdrop-filter:var(--glass-blur);
  border:1px solid var(--glass-line);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.62),
    0 1px 2px rgba(44,37,40,.06),
    0 10px 30px -8px rgba(44,37,40,.24),
    0 30px 60px -22px rgba(44,37,40,.20);
}
.tab{
  display:grid;place-items:center;gap:3px;align-content:center;
  color:var(--ink-28);position:relative;border-radius:var(--r-pill);
  transition:color .18s var(--ease),transform .14s var(--ease);
}
.tab svg{width:20px;height:20px;fill:none;stroke:currentColor;stroke-width:1.5;
  stroke-linejoin:round;stroke-linecap:round}
.tab span{font-size:10px;letter-spacing:.02em}
.tab[aria-current="true"]{color:var(--ink)}
.tab:active{transform:scale(.93)}
.tab .pip{
  position:absolute;top:11px;left:50%;margin-left:8px;
  width:5px;height:5px;border-radius:var(--r-pill);background:var(--flag);
}

/* ── the way in ──────────────────────────────────────────────────────────── */

/* No title card. The cover photograph is already there and the writing lands
   on it — the app is running when you arrive. */
.in-1{animation:up .5s var(--ease) both}
.in-2{animation:up .5s var(--ease) .07s both}
.in-3{animation:up .5s var(--ease) .13s both}
@keyframes up{from{opacity:0;transform:translateY(12px)}to{opacity:1;transform:none}}

@media (prefers-reduced-motion:reduce){
  *,*::before,*::after{animation-duration:.01ms!important;transition-duration:.01ms!important}
}
